shadcn-ui for Phoenix shadix.workinghypothes.is
elixir phoenix shadcn
README.md

Packaged consumer gate #

Run from the repository root with the supported mise tools installed:

mise exec -- node test/consumer/run.mjs

Install Chromium once with cd test/consumer && npm ci && npx playwright install chromium, or set CHROMIUM_BIN to an installed browser. Node dependencies and the consumer's Hex dependencies are pinned in lockfiles. CI runs the identical runner over these two dependency profiles, each with both Nova and Vega:

Profile LiveView Phoenix Tailwind Hex lockfile
minimum 1.2.9 1.8.9 4.2.3 fixture/mix.minimum.lock
locked 1.2.11 1.8.9 4.2.3 fixture/mix.lock

minimum exercises the patched LiveView baseline and the documented Tailwind minimum. It does not mean that every dependency is at its oldest supported version. The remaining Hex versions are identical across profiles; mix deps.get --check-locked rejects dependency resolution drift. The npm lockfile is shared. To debug one profile, use CONSUMER_PROFILES=minimum mise exec -- node test/consumer/run.mjs.

The package declares Elixir ~> 1.20, LiveView ~> 1.2 and >= 1.2.9, and Phoenix ~> 1.8.9 in mix.exs. Local mise pins Elixir 1.20.1 / OTP 29.0.2; the CI recipe uses Elixir 1.20.1 / OTP 27. These are explicit gate configurations, not an exhaustive supported Phoenix, LiveView, Elixir, or OTP matrix, nor a recommendation to deploy older versions without reviewing their security advisories.

Both fixtures pin Bandit 1.12.5, Plug 1.19.5, and HPAX 1.0.4. These versions replace pins affected by the following published advisories; this is a tested dependency baseline, not a guarantee against future advisories:

  • LiveView 1.2.9 fixes externally influenced redirect targets containing ASCII control characters (EEF-CVE-2026-64941).
  • Phoenix 1.8.9 fixes unbounded channel joins and unsafe Presence keys (transport advisory, Presence advisory).
  • Bandit 1.12.5 includes fixes for fragmented WebSocket CPU exhaustion, HTTP/2 flow-control starvation, and HTTP/2 header validation (65623, 74836, 75484).
  • Plug 1.19.5 includes fixes for nested parameter decoding, cookie attribute injection, and multipart header limits (54892, 56813, 56814).
  • HPAX 1.0.4 bounds HPACK integer decoding (EEF-CVE-2026-58226).

The runner builds a real Hex tarball without regenerating its registry, extracts its publishable payload into a temporary directory, and installs that package in four isolated Phoenix applications. For each profile and style it:

  • Runs shadix.init with Acme.Design and a custom component directory, then adds every packaged registry entry using persisted configuration.
  • Repeats installation and checks that customized components, hooks, theme CSS, and configuration remain byte-for-byte intact.
  • Compiles all copied modules with warnings as errors, extracts LiveView colocated CSS, builds it with Tailwind, and bundles all copied hooks.
  • Opens the real generated app in Chromium and checks computed styling, utility overrides, and a dialog containing a select: change validation, server reset, submission, Escape dismissal, and focus return.
  • Repeats that workflow in light/dark at 1280/320 CSS pixels, with 200% root text sizing, and with forced-colors emulation at both widths: ten browser scenarios per profile/style, forty total. Checks also cover labeled text input, native checkbox/switch keyboard state, disabled controls and geometry. The narrow viewport is a reflow equivalent, not native browser zoom. Known forced-colors control-visibility findings remain in docs/ACCESSIBILITY.md; these checks do not claim visual conformance.

Each run creates its own tmp/consumer-* directory, including dependency and build outputs. A failed run retains its artifacts and prints their location; successful runs clean up unless CONSUMER_KEEP_WORKSPACE=1 is set. The runner does not require vendor/, the docs site, or repository stylesheet aggregators. It needs registry/network access for package dependencies on a clean machine.