Own the interface primitives instead of vendoring them from shadcn - #605
Merged
Merged
Conversation
`app/src/components/ui` was treated as somebody else's code: a `components.json` naming the shadcn registry, the `shadcn` CLI in the app's dependencies, and a Biome exclusion that skipped the whole directory for both formatting and linting. Nothing re-pulled from that upstream, so the arrangement bought no updates; it only meant a `shadcn add` would silently revert anything we changed there, and that a quarter of the interface went unformatted and unchecked. The primitives are ours now. The manifest and the CLI are gone -- the CLI sat in `dependencies` rather than `devDependencies`, so it was also shipping a build tool into the runtime tree, which is most of the lockfile this removes. `@shadcn/react` stays: that is a real package the app imports. With the directory checked like everything else, one genuine defect surfaced and is fixed: a field's error list keyed its items by array index rather than by the message, so React reused rows when the set of errors changed. Three accessibility rules are turned off for this directory by name, because they read a reusable primitive as a finished page: a generic `Label` takes its `htmlFor` from the caller, and `role` on a styled wrapper is the component's own interface rather than a missing `fieldset`. Naming three rules in one directory is a decision somebody can review; excluding the directory outright was not.
davidmckayv
requested review from
MikeRyanDev,
guidovizoso,
mxmzb and
tylerslaton
as code owners
September 18, 2026 16:20
9 tasks
Removing it broke the build. `app/src/styles.css` imports `shadcn/tailwind.css`, so the package is a real build input rather than only the CLI that copies components in -- a distinction the first pass missed by looking for TypeScript imports and not CSS ones. What removes the vendoring is `components.json`, which is the file `shadcn add` reads to know where to write; without it there is no command that can overwrite these primitives. The package stays, and the comment in `styles.css` that told the next person not to edit a primitive because an upstream would overwrite it is no longer true, so it says what is true now.
Contributor
Author
|
Correcting the PR body: the |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
app/src/components/uiwas treated as vendored code:app/components.jsonpointing at the shadcn registry, theshadcnCLI in the app's dependencies, and a Biome exclusion (!app/src/components/ui) that skipped the directory for both formatting and linting.Nothing ever re-pulled from that upstream, so the arrangement bought no updates. What it did buy: a
shadcn add <component>would silently revert anything we changed there, and 25 files — a quarter of the interface — went unformatted and unchecked. That came up reviewing #600, which fixes a real bug inui/sidebar.tsxand would have been reverted by the nextshadcn add sidebar.What changed
app/components.jsonand theshadcnCLI dependency. The CLI was independencies, notdevDependencies, so it was shipping a build tool into the runtime dependency tree — that is most of the ~300 lockfile lines this deletes.@shadcn/reactstays: that one is a real package the app imports (chat-transcript,message-scroller,questionnaire).field.tsxkeyed its error list by array index instead of by the message, so React reused rows when the error set changed.useSemanticElements,noLabelWithoutControl,useKeyWithClickEvents): they read a reusable primitive as if it were a finished page — a genericLabeltakeshtmlForfrom its caller, androleon a styled wrapper is the component's interface, not a missing<fieldset>. Swapping those elements would change UA styling across the design system. Three named rules in one directory is a decision somebody can review; excluding the directory outright was not.Checks: format clean,
biome lint --error-on-warningsclean across 826 files, app typecheck 0 errors, 839 app tests pass.