Conversation
Tracks the effort to catch up with the modern shadcn/ui ecosystem: docs refresh, registry modernization, styling refresh, and Base UI support. Work merges into the long-running 'next' branch. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Tailwind v3 site is now frozen; a banner above the header points visitors to the Tailwind v4 documentation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Installation now documents the registry-based install flow and requirements instead of only deferring to shadcn/ui. Removes year-old "New" labels from the sidebar config. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Kbd, Control Group, Input Base and Combobox predate their shadcn/ui equivalents. Each page now leads with a prominent callout recommending the official version; the ui-x components remain provided as-is. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
docs: documentation refresh (overhaul phase 1)
Add aria-invalid destructive ring support via has-[[data-slot][aria-invalid=true]], port current Input/Textarea classes (file:inline-flex file:h-7, field-sizing-content, min-w-0) and InputGroupAddon typography onto adornments. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace calendar with shadcn/ui's current react-day-picker v9 implementation (getDefaultClassNames, --cell-size sizing, CalendarDayButton, native dropdown styling) and drop the Select registry dependency. Update date picker content to the current popover idiom (transform origin, outline-hidden). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Port current Command item/group classes (outline-hidden, svg sizing and muted icon color, text-xs group headings), popover transform origin on content, and the Spinner loading idiom. Drop stale focus ring from kbd (pointer-events-none element) and add the current svg sizing rule. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adopt the latest shadcn/ui focus ring and aria-invalid patterns on DropzoneZone, and switch dropzone, file-list, and badge-group to Icon-suffixed lucide imports. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
feat: refresh component styling to match latest shadcn/ui
Supersedes the Radix + Base UI dual-support plan. Phase 4 becomes a single migration: drop Radix entirely, port components to Base UI with nova styling from the base-nova preset sources, and rebuild the docs site on fumadocs (following shadcn's own stack, including Next 16). Marks Phase 3 (new-york-v4 style refresh, PR #55) complete as the final Radix-era snapshot and adds a keep/drop audit table for the component migration. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace the Radix-based vendored ui components with CLI-installed base-nova sources (Base UI primitives + nova style), update consumers from asChild to render props, and rebuild registry payloads. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
InputBase is now fluid (w-full) like shadcn's nova Input, so demos constrain width at the example layer instead, matching shadcn's preview approach. Also forward className from DatePickerInput to the outer InputBase so width utilities size the visible input. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Vercel deploys fail on a FULL TURBO cache hit because the build tasks
declare no outputs, so turbo replays the logs without restoring the
.next directory ("The Next.js output directory .next was not found").
Declare .next (and v4's velite/registry artifacts) as task outputs so
cached runs restore them.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
feat(v4): migrate to Base UI primitives and nova style
Replace the velite content pipeline with fumadocs-core and fumadocs-mdx, matching the infrastructure used by ui.shadcn.com: - Move MDX content to content/docs with meta.json ordering; sidebar, pager and command menu are now driven by the fumadocs page tree - Rebuild docs routes on source.generateParams/getPage with static generation, and add an /api/search route via createFromSource - Port mdx-components, ComponentPreview/ComponentSource and CodeBlockCommand to RSC with rehype-pretty-code highlighting - Delete velite.config.ts, the custom rehype pipeline and docs config - Upgrade to Next 16 and rewrite the eslint config as native flat config; new react-hooks v6 rules downgraded to warn for now - Wrap the command palette content in a Command root at the call site; the nova CommandDialog no longer provides one, which crashed the renderer when opening search Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace the retained ui-x docs chrome with a faithful port of shadcn/ui's own site UI on top of the fumadocs migration: - Port shadcn's site header, main/mobile nav, command palette, docs sidebar, TOC rail and pager, keeping ui-x branding, version dropdown and GitHub links - Port shadcn's mdx components and code pipeline: CodeBlockCommand with package-manager tabs, CodeTabs (CLI/Manual), collapsible component source, ComponentPreview with View Code gradient - Adopt shadcn's typeset typography, code themes (vesper / github-light-default) and surface tokens - Convert ported Radix idioms to Base UI (data-active, data-open, render props) - Remove orphaned velite-era components (layout/*, toc, pager, code-block, underlined-tabs, nav config) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
BProgress's Next.js integration page (bprogress/next.mdx) was being flattened into the Components sidebar as its own top-level entry. Add getOwnPagesFromFolder, which only surfaces a folder's index page for nested sub-folders instead of recursing into them, matching how shadcn/ui keeps framework-specific sub-pages (e.g. dark-mode/next) out of the sidebar and reachable only via in-page linked cards. Command palette search keeps using the recursive getPagesFromFolder so these sub-pages remain findable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CommandInput (ui/command.tsx) already renders its own bordered InputGroup with a search icon. The command menu's Command className was additionally putting a border and background on the outer command-input-wrapper div, producing two nested boxes that looked like a stacked, duplicate input. Drop the wrapper override and size the InputGroup itself instead. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pages already live under the "Primitives" sidebar section, so repeating the word in every title (e.g. "Combobox Primitive") was redundant. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
feat(v4): migrate docs to fumadocs and adopt shadcn's site design
shadcn now supports installing directly from a public GitHub repo's registry.json (no build/publish step). Add a root registry.json that includes apps/v4/registry.json, drop the shadcn build step and the committed apps/v4/public/r/*.json output (the docs site's live previews never depended on it), update every doc's install snippet to `npx shadcn@latest add junwen-k/ui-x/<item>`, and add a CI job that runs `shadcn registry validate` against the pushed commit. Less code, one source of truth. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Root turbo.json only declares .next/** as the build task's output, so a full cache hit restores .next but skips regenerating .contentlayer (contentlayer2 build never re-runs). Next's file tracing then can't find .contentlayer/generated/Doc/_index.json and the Vercel build errors out. This has been failing intermittently on every v3-ui-x deploy that hits a warm cache (fast ~1m builds in the deploy history, vs. ~5m on a real rebuild). Add an apps/v3/turbo.json overriding the build task's outputs to also include .contentlayer/**, so cache replays restore it too. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
feat(registry): migrate to shadcn GitHub registry, drop build step
…ings
TabsContent lacked min-w-0, so its flex item's default content-based
min-width kept long unbreakable command blocks from shrinking inside
Tabs, overflowing the viewport on narrow install snippets.
Button instances rendered as Next.js Link now pass nativeButton={false}
per Base UI's custom-links guidance, since they no longer render a
native <button> element.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The docs tabs layout breakage was not a source bug — the dev server was serving stale compiled CSS predating the shadcn/tailwind.css import, so the data-horizontal custom variant never applied. A fresh CSS compile resolves it; tabs.tsx now matches shadcn base-nova upstream exactly. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
No pointer to the frozen v3-ui-x.junwen-k.dev registry from the changelog going forward — the clean-cut policy already means ui-x isn't maintaining or promoting the old version, so there's nothing to advertise. The old deployment keeps serving on its own for anyone who already has the URL. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
docs(changelog): drop the radix git-tag plan for a live registry pointer
Replace the orphaned static public/llms.txt with a dynamically generated /llms.txt index and /llms-full.txt, plus a per-page raw markdown export at /docs/<slug>.md, so the LLM docs can never drift from the sidebar again. Since apps/v4 only depends on fumadocs-core/-mdx (headless, no fumadocs-ui), the "Copy Page" / "Open in ChatGPT/Claude/ GitHub" control shadcn shows on each doc page is rebuilt from ui-x's own Button/ButtonGroup/DropdownMenu and the existing copyToClipboard util, rather than pulling in fumadocs-ui. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
feat(docs): add shadcn-style llms.txt support and page actions
Follow shadcn's own approach exactly: a "[llms.txt](/llms.txt)" link entry in meta.json's pages array, which fumadocs-core's loader turns into a page-tree node without a real content file. Flows through the desktop sidebar, mobile nav, and command palette for free since they all read from the same tree — no component changes needed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
docs: surface llms.txt in the docs sidebar
…primitives Primitive demos previously rendered with no visual styling, out of step with the shadcn-look Components section. Style all 6 primitive demos (date-picker, date-time-field, date-time-range-field, dropzone, password-input, phone-input) to match their styled sibling components, and add an "Unstyled" callout on each primitive doc page linking to the ready-to-use styled version. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Styling the primitive demos to look like their shadcn siblings blurred
the distinction the callout itself makes ("this is unstyled, see the
styled version"). Revert all 6 demos back to plain unstyled markup;
dropzone previously had no example at all, so it keeps a bare
unstyled demo instead of none.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
docs(primitives): style demos with shadcn Tailwind and flag unstyled primitives
shadcn's own apps/v4 has no equivalent (checked their repo and live site — neither /robots.txt nor /sitemap.xml resolve), so this follows idiomatic Next.js MetadataRoute conventions instead. The sitemap walks source.getPages() so it tracks the fumadocs page tree the same way llms.txt does, and can't drift from the sidebar. Closes the last open Phase 1 item in ROADMAP.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
feat(docs): add sitemap and robots routes for the v4 site
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Fixes surfaced by a full component/docs audit ahead of the next -> main merge: broken installation links, leftover Tailwind styling in an unstyled primitive demo, the virtualizer/virtualized naming mismatch across demos and docs, a stale changelog section on the timeline page, nova styling drift in dropzone and phone-input, a dead null-check in useVirtualized(), missing Accessibility sections on confirmer and wheel-picker docs, and a registry:validate script for local registry checks. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The previous commit picked up only the virtualizer->virtualized file renames; the accompanying content edits (naming, docs, styling, and the registry:validate script) were left unstaged by a lint-staged stash/restore hiccup. This commit lands that content. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
4 tasks
The guard is unreachable in isolation (VirtualizedContext's default is a real object, never null), but sortable.tsx's useSortable() has the identical shape and every other "must be used within" hook in the registry follows the same throw-guard pattern. Removing it only here broke consistency rather than fixing a real bug. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Drop DropzoneGroup, DropzoneTitle, DropzoneDescription and DropzoneUploadIcon in favor of shadcn/ui's Empty component. Dropzone now covers only the interactive parts; the zone's icon, title and description are composed with Empty/EmptyHeader/EmptyMedia/EmptyTitle/EmptyDescription. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Restore DropzoneUploadIcon as a thin, behavior-only wrapper. The icon swap reads the primitive's drag context (DragAccepted/DragRejected/ DragDefault), so it's genuine Dropzone behavior rather than styling Empty owns — the same principle DatePicker follows when it wraps Calendar/DateField to bind primitive context. Title and description stay composed with Empty directly. Demos, docs and the changelog now render the icon via <EmptyMedia variant="icon"><DropzoneUploadIcon /></EmptyMedia> instead of inlining the primitive drag-state blocks. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…orting Drop the thin re-export wrappers that only renamed a data-slot without adding behavior, styling, or a composed default — these are better composed from the outside, matching how Date Picker already composes InputGroup and Calendar directly. - password-input: remove PasswordInputAdornment and the unused PasswordInputAdornmentButton; demos compose InputGroupAddon directly - phone-input: remove PhoneInputCountrySelectTrigger; demos compose the styled SelectTrigger directly - docs: update Usage, Accessibility and API Reference accordingly Behavioral wrappers (PhoneInputCountrySelect/Value/Content, the toggle, etc.) are unchanged — they wire context, styling or defaults and stay. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Capture the project philosophy and API-design rules as the default prompt for agents and contributors: ui-x as a natural extension of shadcn (not a fork), Base UI + base-nova only, the primitive/styled two-layer architecture, and — front and center — the wrapping principle (wrap + re-export only for behavior/styling/composed defaults; compose cosmetic parts from the outside) that the component audit produced. Also add .mcp.json so agents get live shadcn registry access. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Not every component is primitive + styled: document the three real shapes (styled composition, primitive+styled, library-adapter primitive). - Lead with the library-first philosophy — lean on popular headless libraries (react-dropzone, react-phone-number-input, timescape, …) and only author behavior on Base UI when none fits. - Reframe "Base UI only" as "Base UI, not Radix" (we do use domain libs). - Trim verbosity and soften the rulebook tone into principles + a short hard-rules list. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
fix: address audit findings ahead of next -> main merge
junwen-k
marked this pull request as ready for review
July 19, 2026 13:05
Vercel auto-detects pnpm 9 for this project (old project, lockfileVersion 9.0), against the repo's pnpm@10.34.5 pin. The version drift leaves the pnpm store inconsistent across builds, which intermittently fails install with an ENOENT on the content-addressable store index. Override the install command to run corepack, which reads the version from package.json's packageManager field — one source of truth, no hardcoded version to keep in sync. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
fix(ci): pin Vercel's pnpm to the packageManager field via corepack
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.
Summary
Final ship PR for the ui-x overhaul tracked in
ROADMAP.md. Opened as a draft so the fullmain...nextdiff can be reviewed in one place before merging — do not merge yet, this is for review purposes while a final component-by-component audit runs.Highlights:
@radix-ui/*packages remain.apps/v3(Tailwind v3 app) removed from the monorepo; the deployedv3-ui-x.junwen-k.devbuild keeps serving independently.See
ROADMAP.mdfor the full history and decision log.Test plan
nexton a Vercel preview: full docs smoke test, zero console errors🤖 Generated with Claude Code