From b2cc0dfe59009d72c9e1db1df5948b44ed57190c Mon Sep 17 00:00:00 2001 From: Ahmed Zougari Date: Sun, 15 Mar 2026 06:00:58 +0000 Subject: [PATCH 01/12] fix(docs): update tanstack commands (#10045) --- apps/v4/content/docs/installation/tanstack.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/v4/content/docs/installation/tanstack.mdx b/apps/v4/content/docs/installation/tanstack.mdx index e5f63ee5be..8d6ed917ab 100644 --- a/apps/v4/content/docs/installation/tanstack.mdx +++ b/apps/v4/content/docs/installation/tanstack.mdx @@ -16,13 +16,13 @@ description: Install and configure shadcn/ui for TanStack Start. Run the following command to create a new TanStack Start project with shadcn/ui: ```bash -npx shadcn@latest init -t tanstack +npx shadcn@latest init -t start ``` **For a monorepo project, use `--monorepo` flag:** ```bash -npx shadcn@latest init -t tanstack --monorepo +npx shadcn@latest init -t start --monorepo ``` ### Add Components From a97ebe54f1824032d8ad00d1d0c079e3dc6f52d7 Mon Sep 17 00:00:00 2001 From: shadcn Date: Sun, 15 Mar 2026 10:01:15 +0400 Subject: [PATCH 02/12] fix: bundle @antfu/ni to resolve tinyexec missing module error (#10041) * fix: bundle @antfu/ni to resolve tinyexec missing module error Fixes #10028. Co-Authored-By: Claude Opus 4.6 (1M context) * chore: changeset Co-Authored-By: Claude Opus 4.6 (1M context) --------- Co-authored-by: Claude Opus 4.6 (1M context) --- .changeset/fix-tinyexec-missing.md | 5 +++++ packages/shadcn/package.json | 2 +- packages/shadcn/tsup.config.ts | 3 +++ pnpm-lock.yaml | 14 +++++++------- 4 files changed, 16 insertions(+), 8 deletions(-) create mode 100644 .changeset/fix-tinyexec-missing.md diff --git a/.changeset/fix-tinyexec-missing.md b/.changeset/fix-tinyexec-missing.md new file mode 100644 index 0000000000..0752ee6eec --- /dev/null +++ b/.changeset/fix-tinyexec-missing.md @@ -0,0 +1,5 @@ +--- +"shadcn": patch +--- + +Bundle @antfu/ni and tinyexec to fix missing module error with npx diff --git a/packages/shadcn/package.json b/packages/shadcn/package.json index 3d8390328b..1cf46c7a81 100644 --- a/packages/shadcn/package.json +++ b/packages/shadcn/package.json @@ -79,7 +79,6 @@ "mcp:inspect": "pnpm dlx @modelcontextprotocol/inspector node dist/index.js mcp" }, "dependencies": { - "@antfu/ni": "^25.0.0", "@babel/core": "^7.28.0", "@babel/parser": "^7.28.0", "@babel/plugin-transform-typescript": "^7.28.0", @@ -116,6 +115,7 @@ "zod-to-json-schema": "^3.24.6" }, "devDependencies": { + "@antfu/ni": "^25.0.0", "@types/babel__core": "^7.20.5", "@types/fs-extra": "^11.0.4", "@types/prompts": "^2.4.9", diff --git a/packages/shadcn/tsup.config.ts b/packages/shadcn/tsup.config.ts index 12cb99bf2d..e7a411da60 100644 --- a/packages/shadcn/tsup.config.ts +++ b/packages/shadcn/tsup.config.ts @@ -19,6 +19,9 @@ export default defineConfig({ target: "esnext", outDir: "dist", treeshake: true, + // Bundle @antfu/ni and its dependency tinyexec to avoid + // module resolution failures with npx temporary installs. + noExternal: ["@antfu/ni", "tinyexec"], onSuccess: async () => { copyFileSync("src/tailwind.css", "dist/tailwind.css") }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4f89d549ec..657973e014 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -359,9 +359,6 @@ importers: packages/shadcn: dependencies: - '@antfu/ni': - specifier: ^25.0.0 - version: 25.0.0 '@babel/core': specifier: ^7.28.0 version: 7.28.0 @@ -465,6 +462,9 @@ importers: specifier: ^3.24.6 version: 3.24.6(zod@3.25.76) devDependencies: + '@antfu/ni': + specifier: ^25.0.0 + version: 25.0.0 '@types/babel__core': specifier: ^7.20.5 version: 7.20.5 @@ -12067,7 +12067,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.39.0(eslint@9.26.0(hono@4.11.7)(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.26.0(hono@4.11.7)(jiti@2.6.1)))(eslint@9.26.0(hono@4.11.7)(jiti@2.6.1)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.39.0(eslint@9.26.0(hono@4.11.7)(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.26.0(hono@4.11.7)(jiti@2.6.1)): dependencies: debug: 3.2.7 optionalDependencies: @@ -12078,7 +12078,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.54.0(eslint@9.26.0(hono@4.11.7)(jiti@1.21.7))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.26.0(hono@4.11.7)(jiti@1.21.7)))(eslint@9.26.0(hono@4.11.7)(jiti@1.21.7)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.54.0(eslint@9.26.0(hono@4.11.7)(jiti@1.21.7))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.26.0(hono@4.11.7)(jiti@1.21.7)): dependencies: debug: 3.2.7 optionalDependencies: @@ -12100,7 +12100,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.26.0(hono@4.11.7)(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.39.0(eslint@9.26.0(hono@4.11.7)(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.26.0(hono@4.11.7)(jiti@2.6.1)))(eslint@9.26.0(hono@4.11.7)(jiti@2.6.1)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.39.0(eslint@9.26.0(hono@4.11.7)(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.26.0(hono@4.11.7)(jiti@2.6.1)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -12129,7 +12129,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.26.0(hono@4.11.7)(jiti@1.21.7) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.54.0(eslint@9.26.0(hono@4.11.7)(jiti@1.21.7))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.26.0(hono@4.11.7)(jiti@1.21.7)))(eslint@9.26.0(hono@4.11.7)(jiti@1.21.7)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.54.0(eslint@9.26.0(hono@4.11.7)(jiti@1.21.7))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.26.0(hono@4.11.7)(jiti@1.21.7)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 From e2d36a3a7d39d08845c2c2ebfaddfc647f456178 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 15 Mar 2026 10:07:48 +0400 Subject: [PATCH 03/12] chore(release): version packages (#10046) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .changeset/fix-tinyexec-missing.md | 5 ----- apps/v4/package.json | 2 +- packages/shadcn/CHANGELOG.md | 6 ++++++ packages/shadcn/package.json | 2 +- pnpm-lock.yaml | 10 +++++----- 5 files changed, 13 insertions(+), 12 deletions(-) delete mode 100644 .changeset/fix-tinyexec-missing.md diff --git a/.changeset/fix-tinyexec-missing.md b/.changeset/fix-tinyexec-missing.md deleted file mode 100644 index 0752ee6eec..0000000000 --- a/.changeset/fix-tinyexec-missing.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"shadcn": patch ---- - -Bundle @antfu/ni and tinyexec to fix missing module error with npx diff --git a/apps/v4/package.json b/apps/v4/package.json index 3f5a441df2..af10a7627b 100644 --- a/apps/v4/package.json +++ b/apps/v4/package.json @@ -76,7 +76,7 @@ "rehype-pretty-code": "^0.14.1", "rimraf": "^6.0.1", "server-only": "^0.0.1", - "shadcn": "4.0.7", + "shadcn": "4.0.8", "shiki": "^1.10.1", "sonner": "^2.0.0", "swr": "^2.3.6", diff --git a/packages/shadcn/CHANGELOG.md b/packages/shadcn/CHANGELOG.md index 741fafbbe8..8a9c7bdc3f 100644 --- a/packages/shadcn/CHANGELOG.md +++ b/packages/shadcn/CHANGELOG.md @@ -1,5 +1,11 @@ # @shadcn/ui +## 4.0.8 + +### Patch Changes + +- [#10041](https://github.com/shadcn-ui/ui/pull/10041) [`a97ebe54f1824032d8ad00d1d0c079e3dc6f52d7`](https://github.com/shadcn-ui/ui/commit/a97ebe54f1824032d8ad00d1d0c079e3dc6f52d7) Thanks [@shadcn](https://github.com/shadcn)! - Bundle @antfu/ni and tinyexec to fix missing module error with npx + ## 4.0.7 ### Patch Changes diff --git a/packages/shadcn/package.json b/packages/shadcn/package.json index 1cf46c7a81..52fe4fed2a 100644 --- a/packages/shadcn/package.json +++ b/packages/shadcn/package.json @@ -1,6 +1,6 @@ { "name": "shadcn", - "version": "4.0.7", + "version": "4.0.8", "description": "Add components to your apps.", "publishConfig": { "access": "public" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 657973e014..01336aa661 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -278,7 +278,7 @@ importers: specifier: ^0.0.1 version: 0.0.1 shadcn: - specifier: 4.0.7 + specifier: 4.0.8 version: link:../../packages/shadcn shiki: specifier: ^1.10.1 @@ -12067,7 +12067,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.39.0(eslint@9.26.0(hono@4.11.7)(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.26.0(hono@4.11.7)(jiti@2.6.1)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.39.0(eslint@9.26.0(hono@4.11.7)(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.26.0(hono@4.11.7)(jiti@2.6.1)))(eslint@9.26.0(hono@4.11.7)(jiti@2.6.1)): dependencies: debug: 3.2.7 optionalDependencies: @@ -12078,7 +12078,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.54.0(eslint@9.26.0(hono@4.11.7)(jiti@1.21.7))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.26.0(hono@4.11.7)(jiti@1.21.7)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.54.0(eslint@9.26.0(hono@4.11.7)(jiti@1.21.7))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.26.0(hono@4.11.7)(jiti@1.21.7)))(eslint@9.26.0(hono@4.11.7)(jiti@1.21.7)): dependencies: debug: 3.2.7 optionalDependencies: @@ -12100,7 +12100,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.26.0(hono@4.11.7)(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.39.0(eslint@9.26.0(hono@4.11.7)(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.26.0(hono@4.11.7)(jiti@2.6.1)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.39.0(eslint@9.26.0(hono@4.11.7)(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.26.0(hono@4.11.7)(jiti@2.6.1)))(eslint@9.26.0(hono@4.11.7)(jiti@2.6.1)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -12129,7 +12129,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.26.0(hono@4.11.7)(jiti@1.21.7) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.54.0(eslint@9.26.0(hono@4.11.7)(jiti@1.21.7))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.26.0(hono@4.11.7)(jiti@1.21.7)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.54.0(eslint@9.26.0(hono@4.11.7)(jiti@1.21.7))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.26.0(hono@4.11.7)(jiti@1.21.7)))(eslint@9.26.0(hono@4.11.7)(jiti@1.21.7)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 From 6e476e47560c6c79024f9e3bf00564c22ab4b238 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Sun, 15 Mar 2026 11:06:56 +0400 Subject: [PATCH 04/12] Rename @hooks registry to @shadcnhooks (#10036) * Initial plan * Rename @hooks registry to @shadcnhooks Co-authored-by: shadcn <124599+shadcn@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: shadcn <124599+shadcn@users.noreply.github.com> --- apps/v4/public/r/registries-legacy.json | 2 +- apps/v4/public/r/registries.json | 2 +- apps/v4/registry/directory.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/v4/public/r/registries-legacy.json b/apps/v4/public/r/registries-legacy.json index 995f92c5a3..1c25f0bd89 100644 --- a/apps/v4/public/r/registries-legacy.json +++ b/apps/v4/public/r/registries-legacy.json @@ -41,7 +41,7 @@ "@gaia": "https://ui.heygaia.io/r/{name}.json", "@glass-ui": "https://glass-ui.crenspire.com/r/{name}.json", "@heseui": "https://www.heseui.com/r/{name}.json", - "@hooks": "https://shadcn-hooks.com/r/{name}.json", + "@shadcnhooks": "https://shadcn-hooks.com/r/{name}.json", "@intentui": "https://intentui.com/r/{name}", "@kibo-ui": "https://www.kibo-ui.com/r/{name}.json", "@kanpeki": "https://kanpeki.vercel.app/r/{name}.json", diff --git a/apps/v4/public/r/registries.json b/apps/v4/public/r/registries.json index f2c0d2e4bc..c3cd581e38 100644 --- a/apps/v4/public/r/registries.json +++ b/apps/v4/public/r/registries.json @@ -252,7 +252,7 @@ "description": "Ready-to-use foundation components/blocks built on top of shadcn/ui." }, { - "name": "@hooks", + "name": "@shadcnhooks", "homepage": "https://shadcn-hooks.com", "url": "https://shadcn-hooks.com/r/{name}.json", "description": "A comprehensive React Hooks Collection built with Shadcn." diff --git a/apps/v4/registry/directory.json b/apps/v4/registry/directory.json index 3ca3c1c4a0..1f8e7605ab 100644 --- a/apps/v4/registry/directory.json +++ b/apps/v4/registry/directory.json @@ -295,7 +295,7 @@ "logo": "" }, { - "name": "@hooks", + "name": "@shadcnhooks", "homepage": "https://shadcn-hooks.com", "url": "https://shadcn-hooks.com/r/{name}.json", "description": "A comprehensive React Hooks Collection built with Shadcn.", From 1be8f98c46e9bc7a40229a6e33f6c72e876a36e2 Mon Sep 17 00:00:00 2001 From: shadcn Date: Sun, 15 Mar 2026 11:07:13 +0400 Subject: [PATCH 05/12] feat: add namespace validation for registries (#10033) --- .github/workflows/validate-registries.yml | 40 ++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/.github/workflows/validate-registries.yml b/.github/workflows/validate-registries.yml index f507116a11..fc86ae3317 100644 --- a/.github/workflows/validate-registries.yml +++ b/.github/workflows/validate-registries.yml @@ -16,7 +16,7 @@ jobs: check-registry-sync: if: github.event_name == 'pull_request' runs-on: ubuntu-latest - name: Check registry sync + name: check-registry-sync permissions: contents: read pull-requests: write @@ -66,6 +66,44 @@ jobs: with: node-version: 20 + - name: Block reserved registry namespaces + env: + RESERVED_NAMESPACES: "@shadcn,@ui,@blocks,@components,@block,@component,@util,@utils,@registry,@lib,@hook,@hooks,@theme,@themes,@chart,@charts" + run: | + node <<'EOF' + const fs = require("node:fs") + + const files = [ + "apps/v4/public/r/registries.json", + "apps/v4/registry/directory.json", + ] + const reservedNamespaces = new Set( + process.env.RESERVED_NAMESPACES.split(",").filter(Boolean) + ) + + function readNames(filePath) { + return JSON.parse(fs.readFileSync(filePath, "utf8")).map( + (entry) => entry.name + ) + } + + const violations = files.flatMap((filePath) => { + return readNames(filePath) + .filter((name) => reservedNamespaces.has(name)) + .map((name) => `${filePath}: ${name}`) + }) + + if (violations.length > 0) { + console.error("Reserved registry namespaces are not allowed:") + + for (const violation of violations) { + console.error(`- ${violation}`) + } + + process.exit(1) + } + EOF + - uses: pnpm/action-setup@v4 name: Install pnpm id: pnpm-install From e000e178563ba5627af66bf513d54a5ce22995ed Mon Sep 17 00:00:00 2001 From: Frank <97429702+tsubasakong@users.noreply.github.com> Date: Sun, 15 Mar 2026 00:50:47 -0700 Subject: [PATCH 06/12] fix(registry): register next form examples (#10021) --- apps/v4/registry/__index__.tsx | 38 +++++++++++++++++++ .../new-york-v4/examples/_registry.ts | 34 +++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/apps/v4/registry/__index__.tsx b/apps/v4/registry/__index__.tsx index f1f0f65357..2d4efb54ca 100644 --- a/apps/v4/registry/__index__.tsx +++ b/apps/v4/registry/__index__.tsx @@ -4888,6 +4888,44 @@ export const Index: Record> = { categories: undefined, meta: undefined, }, + "form-next-demo": { + name: "form-next-demo", + title: "undefined", + description: "", + type: "registry:example", + registryDependencies: ["field","input","textarea","button","card","spinner"], + files: [{ + path: "registry/new-york-v4/examples/form-next-demo.tsx", + type: "registry:example", + target: "" + }], + component: React.lazy(async () => { + const mod = await import("@/registry/new-york-v4/examples/form-next-demo.tsx") + const exportName = Object.keys(mod).find(key => typeof mod[key] === 'function' || typeof mod[key] === 'object') || item.name + return { default: mod.default || mod[exportName] } + }), + categories: undefined, + meta: undefined, + }, + "form-next-complex": { + name: "form-next-complex", + title: "undefined", + description: "", + type: "registry:example", + registryDependencies: ["field","input","textarea","button","card","spinner","checkbox","dialog","radio-group","select","switch"], + files: [{ + path: "registry/new-york-v4/examples/form-next-complex.tsx", + type: "registry:example", + target: "" + }], + component: React.lazy(async () => { + const mod = await import("@/registry/new-york-v4/examples/form-next-complex.tsx") + const exportName = Object.keys(mod).find(key => typeof mod[key] === 'function' || typeof mod[key] === 'object') || item.name + return { default: mod.default || mod[exportName] } + }), + categories: undefined, + meta: undefined, + }, "form-rhf-demo": { name: "form-rhf-demo", title: "undefined", diff --git a/apps/v4/registry/new-york-v4/examples/_registry.ts b/apps/v4/registry/new-york-v4/examples/_registry.ts index 43ba976275..48e27e2b12 100644 --- a/apps/v4/registry/new-york-v4/examples/_registry.ts +++ b/apps/v4/registry/new-york-v4/examples/_registry.ts @@ -950,6 +950,40 @@ export const examples: Registry["items"] = [ }, ], }, + { + name: "form-next-demo", + type: "registry:example", + registryDependencies: ["field", "input", "textarea", "button", "card", "spinner"], + files: [ + { + path: "examples/form-next-demo.tsx", + type: "registry:example", + }, + ], + }, + { + name: "form-next-complex", + type: "registry:example", + registryDependencies: [ + "field", + "input", + "textarea", + "button", + "card", + "spinner", + "checkbox", + "dialog", + "radio-group", + "select", + "switch", + ], + files: [ + { + path: "examples/form-next-complex.tsx", + type: "registry:example", + }, + ], + }, { name: "form-rhf-demo", type: "registry:example", From d683b05d7fcfea793aac5b39967ef41444eb6b55 Mon Sep 17 00:00:00 2001 From: shadcn Date: Sun, 15 Mar 2026 12:58:00 +0400 Subject: [PATCH 07/12] chore: remove tooltip from mode switcher (#10047) Co-authored-by: Claude Opus 4.6 (1M context) --- apps/v4/components/mode-switcher.tsx | 67 +++++++++++----------------- 1 file changed, 27 insertions(+), 40 deletions(-) diff --git a/apps/v4/components/mode-switcher.tsx b/apps/v4/components/mode-switcher.tsx index d287df42ea..5858decc72 100644 --- a/apps/v4/components/mode-switcher.tsx +++ b/apps/v4/components/mode-switcher.tsx @@ -7,12 +7,6 @@ import { useTheme } from "next-themes" import { cn } from "@/lib/utils" import { useMetaColor } from "@/hooks/use-meta-color" import { Button } from "@/registry/new-york-v4/ui/button" -import { Kbd } from "@/registry/new-york-v4/ui/kbd" -import { - Tooltip, - TooltipContent, - TooltipTrigger, -} from "@/registry/new-york-v4/ui/tooltip" export const DARK_MODE_FORWARD_TYPE = "dark-mode-forward" @@ -35,40 +29,33 @@ export function ModeSwitcher({ }, [resolvedTheme, setTheme]) return ( - - - - - - Toggle Mode D - - + ) } From 6cad52293046fedf342a7c38a3d54b621a5f8978 Mon Sep 17 00:00:00 2001 From: shadcn Date: Sun, 15 Mar 2026 13:02:35 +0400 Subject: [PATCH 08/12] chore: rebuild registry --- .../styles/new-york-v4/form-next-complex.json | 14 +------ .../r/styles/new-york-v4/form-next-demo.json | 4 +- .../public/r/styles/new-york-v4/registry.json | 41 +++++++++++++++++++ .../new-york-v4/examples/_registry.ts | 9 +++- 4 files changed, 53 insertions(+), 15 deletions(-) diff --git a/apps/v4/public/r/styles/new-york-v4/form-next-complex.json b/apps/v4/public/r/styles/new-york-v4/form-next-complex.json index 9c4b29bb2d..750678a7cd 100644 --- a/apps/v4/public/r/styles/new-york-v4/form-next-complex.json +++ b/apps/v4/public/r/styles/new-york-v4/form-next-complex.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "form-next-complex", - "type": "registry:example", "registryDependencies": [ "field", "input", @@ -20,16 +19,7 @@ "path": "registry/new-york-v4/examples/form-next-complex.tsx", "content": "\"use client\"\n\nimport * as React from \"react\"\nimport Form from \"next/form\"\nimport { toast } from \"sonner\"\n\nimport { Button } from \"@/registry/new-york-v4/ui/button\"\nimport { Card, CardContent, CardFooter } from \"@/registry/new-york-v4/ui/card\"\nimport { Checkbox } from \"@/registry/new-york-v4/ui/checkbox\"\nimport {\n Field,\n FieldContent,\n FieldDescription,\n FieldError,\n FieldGroup,\n FieldLabel,\n FieldLegend,\n FieldSeparator,\n FieldSet,\n FieldTitle,\n} from \"@/registry/new-york-v4/ui/field\"\nimport {\n RadioGroup,\n RadioGroupItem,\n} from \"@/registry/new-york-v4/ui/radio-group\"\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@/registry/new-york-v4/ui/select\"\nimport { Spinner } from \"@/registry/new-york-v4/ui/spinner\"\nimport { Switch } from \"@/registry/new-york-v4/ui/switch\"\n\nimport { complexFormAction } from \"./form-next-complex-action\"\nimport { addons, type FormState } from \"./form-next-complex-schema\"\n\nexport default function FormNextComplex() {\n const [formState, formAction, pending] = React.useActionState<\n FormState,\n FormData\n >(complexFormAction, {\n values: {\n plan: \"basic\",\n billingPeriod: \"monthly\",\n addons: [],\n emailNotifications: false,\n },\n errors: null,\n success: false,\n })\n\n React.useEffect(() => {\n if (formState.success) {\n toast.success(\"Preferences saved\", {\n description: \"Your subscription plan has been updated.\",\n })\n }\n }, [formState.success])\n\n return (\n \n \n
\n \n
\n Subscription Plan\n \n Choose your subscription plan.\n \n \n \n \n \n Basic\n \n For individuals and small teams\n \n \n \n \n \n \n \n \n Pro\n \n For businesses with higher demands\n \n \n \n \n \n \n {formState.errors?.plan && (\n {formState.errors.plan[0]}\n )}\n
\n \n \n Billing Period\n \n \n \n \n \n Monthly\n Yearly\n \n \n \n Choose how often you want to be billed.\n \n {formState.errors?.billingPeriod && (\n {formState.errors.billingPeriod[0]}\n )}\n \n \n
\n Add-ons\n \n Select additional features you'd like to include.\n \n \n {addons.map((addon) => (\n \n \n \n {addon.title}\n {addon.description}\n \n \n ))}\n \n {formState.errors?.addons && (\n {formState.errors.addons[0]}\n )}\n
\n \n \n \n \n Email Notifications\n \n \n Receive email updates about your subscription\n \n \n \n \n
\n
\n
\n \n \n \n \n \n
\n )\n}\n", "type": "registry:example" - }, - { - "path": "registry/new-york-v4/examples/form-next-complex-schema.ts", - "content": "import { z } from \"zod\"\n\nexport const formSchema = z.object({\n plan: z\n .string({\n required_error: \"Please select a subscription plan\",\n })\n .min(1, \"Please select a subscription plan\")\n .refine((value) => value === \"basic\" || value === \"pro\", {\n message: \"Invalid plan selection. Please choose Basic or Pro\",\n }),\n billingPeriod: z\n .string({\n required_error: \"Please select a billing period\",\n })\n .min(1, \"Please select a billing period\"),\n addons: z\n .array(z.string())\n .min(1, \"Please select at least one add-on\")\n .max(3, \"You can select up to 3 add-ons\")\n .refine(\n (value) => value.every((addon) => addons.some((a) => a.id === addon)),\n {\n message: \"You selected an invalid add-on\",\n }\n ),\n emailNotifications: z.boolean(),\n})\n\nexport type FormState = {\n values: z.infer\n errors: null | Partial, string[]>>\n success: boolean\n}\n\nexport const addons = [\n {\n id: \"analytics\",\n title: \"Analytics\",\n description: \"Advanced analytics and reporting\",\n },\n {\n id: \"backup\",\n title: \"Backup\",\n description: \"Automated daily backups\",\n },\n {\n id: \"support\",\n title: \"Priority Support\",\n description: \"24/7 premium customer support\",\n },\n] as const\n", - "type": "registry:example" - }, - { - "path": "registry/new-york-v4/examples/form-next-complex-action.ts", - "content": "\"use server\"\n\nimport { formSchema, type FormState } from \"./form-next-complex-schema\"\n\nexport async function complexFormAction(\n _prevState: FormState,\n formData: FormData\n) {\n // Sleep for 1 second\n await new Promise((resolve) => setTimeout(resolve, 1000))\n\n const values = {\n plan: formData.get(\"plan\") as FormState[\"values\"][\"plan\"],\n billingPeriod: formData.get(\"billingPeriod\") as string,\n addons: formData.getAll(\"addons\") as string[],\n emailNotifications: formData.get(\"emailNotifications\") === \"on\",\n }\n\n const result = formSchema.safeParse(values)\n\n if (!result.success) {\n return {\n values,\n success: false,\n errors: result.error.flatten().fieldErrors,\n }\n }\n\n // Do something with the values.\n // Call your database or API here.\n\n return {\n values,\n errors: null,\n success: true,\n }\n}\n", - "type": "registry:example" } - ] + ], + "type": "registry:example" } \ No newline at end of file diff --git a/apps/v4/public/r/styles/new-york-v4/form-next-demo.json b/apps/v4/public/r/styles/new-york-v4/form-next-demo.json index b0d0325ad7..f5ac897d02 100644 --- a/apps/v4/public/r/styles/new-york-v4/form-next-demo.json +++ b/apps/v4/public/r/styles/new-york-v4/form-next-demo.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "form-next-demo", - "type": "registry:example", "registryDependencies": [ "field", "input", @@ -16,5 +15,6 @@ "content": "\"use client\"\n\nimport * as React from \"react\"\nimport Form from \"next/form\"\nimport { toast } from \"sonner\"\n\nimport { Button } from \"@/registry/new-york-v4/ui/button\"\nimport {\n Card,\n CardContent,\n CardDescription,\n CardFooter,\n CardHeader,\n CardTitle,\n} from \"@/registry/new-york-v4/ui/card\"\nimport {\n Field,\n FieldDescription,\n FieldError,\n FieldGroup,\n FieldLabel,\n} from \"@/registry/new-york-v4/ui/field\"\nimport { Input } from \"@/registry/new-york-v4/ui/input\"\nimport {\n InputGroup,\n InputGroupAddon,\n InputGroupText,\n InputGroupTextarea,\n} from \"@/registry/new-york-v4/ui/input-group\"\nimport { Spinner } from \"@/registry/new-york-v4/ui/spinner\"\n\nimport { demoFormAction } from \"./form-next-demo-action\"\nimport { type FormState } from \"./form-next-demo-schema\"\n\nexport default function FormNextDemo() {\n const [formState, formAction, pending] = React.useActionState<\n FormState,\n FormData\n >(demoFormAction, {\n values: {\n title: \"\",\n description: \"\",\n },\n errors: null,\n success: false,\n })\n const [descriptionLength, setDescriptionLength] = React.useState(0)\n\n React.useEffect(() => {\n if (formState.success) {\n toast(\"Thank you for your feedback\", {\n description: \"We'll review your report and get back to you soon.\",\n })\n }\n }, [formState.success])\n\n React.useEffect(() => {\n setDescriptionLength(formState.values.description.length)\n }, [formState.values.description])\n\n return (\n \n \n Bug Report\n \n Help us improve by reporting bugs you encounter.\n \n \n \n
\n \n \n Bug Title\n \n {formState.errors?.title && (\n {formState.errors.title[0]}\n )}\n \n \n Description\n \n setDescriptionLength(e.target.value.length)}\n />\n \n \n {descriptionLength}/100 characters\n \n \n \n \n Include steps to reproduce, expected behavior, and what actually\n happened.\n \n {formState.errors?.description && (\n {formState.errors.description[0]}\n )}\n \n \n
\n
\n \n \n \n \n \n
\n )\n}\n", "type": "registry:example" } - ] + ], + "type": "registry:example" } \ No newline at end of file diff --git a/apps/v4/public/r/styles/new-york-v4/registry.json b/apps/v4/public/r/styles/new-york-v4/registry.json index 2fb79c73ae..bcea5cd601 100644 --- a/apps/v4/public/r/styles/new-york-v4/registry.json +++ b/apps/v4/public/r/styles/new-york-v4/registry.json @@ -3696,6 +3696,47 @@ ], "type": "registry:example" }, + { + "name": "form-next-demo", + "registryDependencies": [ + "field", + "input", + "textarea", + "button", + "card", + "spinner" + ], + "files": [ + { + "path": "registry/new-york-v4/examples/form-next-demo.tsx", + "type": "registry:example" + } + ], + "type": "registry:example" + }, + { + "name": "form-next-complex", + "registryDependencies": [ + "field", + "input", + "textarea", + "button", + "card", + "spinner", + "checkbox", + "dialog", + "radio-group", + "select", + "switch" + ], + "files": [ + { + "path": "registry/new-york-v4/examples/form-next-complex.tsx", + "type": "registry:example" + } + ], + "type": "registry:example" + }, { "name": "form-rhf-demo", "dependencies": ["react-hook-form", "@hookform/resolvers", "zod"], diff --git a/apps/v4/registry/new-york-v4/examples/_registry.ts b/apps/v4/registry/new-york-v4/examples/_registry.ts index 48e27e2b12..ac78c238fc 100644 --- a/apps/v4/registry/new-york-v4/examples/_registry.ts +++ b/apps/v4/registry/new-york-v4/examples/_registry.ts @@ -953,7 +953,14 @@ export const examples: Registry["items"] = [ { name: "form-next-demo", type: "registry:example", - registryDependencies: ["field", "input", "textarea", "button", "card", "spinner"], + registryDependencies: [ + "field", + "input", + "textarea", + "button", + "card", + "spinner", + ], files: [ { path: "examples/form-next-demo.tsx", From 7ffefce9e0a25e8341a95124bea60b68ec7dbb7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?l=C3=A9o?= <143509522+wicki-leonard-emf@users.noreply.github.com> Date: Sun, 15 Mar 2026 12:21:09 +0100 Subject: [PATCH 09/12] feat: add @0unlumen-ui registry (#9970) * feat: add @0unlumen-ui registry * fix: consistent registry name from @0unlumen-ui to @unlumen-ui --- apps/v4/public/r/registries.json | 6 ++++++ apps/v4/registry/directory.json | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/apps/v4/public/r/registries.json b/apps/v4/public/r/registries.json index c3cd581e38..652e11a585 100644 --- a/apps/v4/public/r/registries.json +++ b/apps/v4/public/r/registries.json @@ -11,6 +11,12 @@ "url": "https://ui.8starlabs.com/r/{name}.json", "description": "A set of beautifully designed components designed for developers who want niche, high-utility UI elements that you won't find in standard libraries." }, + { + "name": "@unlumen-ui", + "homepage": "https://ui.unlumen.com", + "url": "https://ui.unlumen.com/r/{name}.json", + "description": "Primitives and components with serious attention to animation and design. Copy, own, ship." + }, { "name": "@auth0", "homepage": "https://auth0.com", diff --git a/apps/v4/registry/directory.json b/apps/v4/registry/directory.json index 1f8e7605ab..891ab13ab3 100644 --- a/apps/v4/registry/directory.json +++ b/apps/v4/registry/directory.json @@ -13,6 +13,13 @@ "description": "A set of beautifully designed components designed for developers who want niche, high-utility UI elements that you won't find in standard libraries.", "logo": " " }, + { + "name": "@unlumen-ui", + "homepage": "https://ui.unlumen.com", + "url": "https://ui.unlumen.com/r/{name}.json", + "description": "Primitives and components with serious attention to animation and design. Copy, own, ship.", + "logo": "" + }, { "name": "@auth0", "homepage": "https://auth0.com", From 4809da6f9caf7cd489a56fd29055f7e6e5ff9e86 Mon Sep 17 00:00:00 2001 From: "atyb a." <180611249+atybdot@users.noreply.github.com> Date: Mon, 16 Mar 2026 10:06:19 +0530 Subject: [PATCH 10/12] feat(colors): add mauve, olive, mist, and taupe color palettes (#10049) * fix:Nuqs adapter scope, select color-format component and color copy-to-clipboard * chore: remove changeset * feat(colors): add mauve, olive, mist, and taupe color palettes --------- Co-authored-by: shadcn --- apps/v4/registry/_legacy-colors.ts | 316 +++++++++++++++++++++++++++++ 1 file changed, 316 insertions(+) diff --git a/apps/v4/registry/_legacy-colors.ts b/apps/v4/registry/_legacy-colors.ts index d5da076ee5..1494a350b1 100644 --- a/apps/v4/registry/_legacy-colors.ts +++ b/apps/v4/registry/_legacy-colors.ts @@ -409,6 +409,322 @@ export const colors = { oklch: "oklch(0.13,0.03,262)", }, ], + mauve: [ + { + scale: 50, + hex: "#fafafb", + rgb: "rgb(250,250,251)", + hsl: "hsl(272.4,15%,98.2%)", + oklch: "oklch(0.98,0.00,310)", + }, + { + scale: 100, + hex: "#f4f2f6", + rgb: "rgb(244,242,246)", + hsl: "hsl(272.4,16.1%,95.8%)", + oklch: "oklch(0.96,0.01,310)", + }, + { + scale: 200, + hex: "#e5e1e8", + rgb: "rgb(229,225,232)", + hsl: "hsl(272.5,13%,89.6%)", + oklch: "oklch(0.92,0.01,310)", + }, + { + scale: 300, + hex: "#d0c9d5", + rgb: "rgb(208,201,213)", + hsl: "hsl(272.6,12.6%,81.2%)", + oklch: "oklch(0.84,0.02,310)", + }, + { + scale: 400, + hex: "#a69bae", + rgb: "rgb(166,155,174)", + hsl: "hsl(272.9,10.6%,64.6%)", + oklch: "oklch(0.70,0.03,310)", + }, + { + scale: 500, + hex: "#81758b", + rgb: "rgb(129,117,139)", + hsl: "hsl(273.2,8.6%,50.1%)", + oklch: "oklch(0.58,0.04,310)", + }, + { + scale: 600, + hex: "#675d70", + rgb: "rgb(103,93,112)", + hsl: "hsl(273.2,9.2%,40.2%)", + oklch: "oklch(0.49,0.03,310)", + }, + { + scale: 700, + hex: "#524959", + rgb: "rgb(82,73,89)", + hsl: "hsl(273.3,9.7%,31.7%)", + oklch: "oklch(0.42,0.03,310)", + }, + { + scale: 800, + hex: "#3d3642", + rgb: "rgb(61,54,66)", + hsl: "hsl(273.3,10.2%,23.6%)", + oklch: "oklch(0.34,0.02,310)", + }, + { + scale: 900, + hex: "#2a252e", + rgb: "rgb(42,37,46)", + hsl: "hsl(273.3,10.9%,16.4%)", + oklch: "oklch(0.28,0.02,310)", + }, + { + scale: 950, + hex: "#161218", + rgb: "rgb(22,18,24)", + hsl: "hsl(273.3,14.1%,8.3%)", + oklch: "oklch(0.19,0.01,310)", + }, + ], + olive: [ + { + scale: 50, + hex: "#f9faf9", + rgb: "rgb(249,250,249)", + hsl: "hsl(136.8,13.4%,97.9%)", + oklch: "oklch(0.98,0.00,155)", + }, + { + scale: 100, + hex: "#f1f4f2", + rgb: "rgb(241,244,242)", + hsl: "hsl(136.9,14.2%,95.2%)", + oklch: "oklch(0.96,0.01,155)", + }, + { + scale: 200, + hex: "#dee5e0", + rgb: "rgb(222,229,224)", + hsl: "hsl(137,10.6%,88.5%)", + oklch: "oklch(0.92,0.01,155)", + }, + { + scale: 300, + hex: "#c4cfc8", + rgb: "rgb(196,207,200)", + hsl: "hsl(137.2,10.3%,79.2%)", + oklch: "oklch(0.84,0.02,155)", + }, + { + scale: 400, + hex: "#94a599", + rgb: "rgb(148,165,153)", + hsl: "hsl(137.8,8.7%,61.4%)", + oklch: "oklch(0.70,0.03,155)", + }, + { + scale: 500, + hex: "#6c8072", + rgb: "rgb(108,128,114)", + hsl: "hsl(138.4,8.6%,46.3%)", + oklch: "oklch(0.58,0.03,155)", + }, + { + scale: 600, + hex: "#56675b", + rgb: "rgb(86,103,91)", + hsl: "hsl(138.4,9.1%,37%)", + oklch: "oklch(0.49,0.03,155)", + }, + { + scale: 700, + hex: "#435147", + rgb: "rgb(67,81,71)", + hsl: "hsl(138.4,9.5%,29.1%)", + oklch: "oklch(0.42,0.02,155)", + }, + { + scale: 800, + hex: "#313c35", + rgb: "rgb(49,60,53)", + hsl: "hsl(138.4,10.2%,21.5%)", + oklch: "oklch(0.34,0.02,155)", + }, + { + scale: 900, + hex: "#222a24", + rgb: "rgb(34,42,36)", + hsl: "hsl(138.5,11.2%,14.8%)", + oklch: "oklch(0.28,0.02,155)", + }, + { + scale: 950, + hex: "#101512", + rgb: "rgb(16,21,18)", + hsl: "hsl(138.4,14.2%,7.3%)", + oklch: "oklch(0.19,0.01,155)", + }, + ], + mist: [ + { + scale: 50, + hex: "#f9fafb", + rgb: "rgb(249,250,251)", + hsl: "hsl(189.3,20.3%,97.9%)", + oklch: "oklch(0.98,0.00,210)", + }, + { + scale: 100, + hex: "#f0f4f5", + rgb: "rgb(240,244,245)", + hsl: "hsl(189.4,21.6%,95.1%)", + oklch: "oklch(0.96,0.01,210)", + }, + { + scale: 200, + hex: "#dce5e6", + rgb: "rgb(220,229,230)", + hsl: "hsl(189.4,16.2%,88.4%)", + oklch: "oklch(0.92,0.01,210)", + }, + { + scale: 300, + hex: "#c1cfd2", + rgb: "rgb(193,207,210)", + hsl: "hsl(189.4,15.8%,79%)", + oklch: "oklch(0.84,0.02,210)", + }, + { + scale: 400, + hex: "#8da5a9", + rgb: "rgb(141,165,169)", + hsl: "hsl(189.3,14%,60.9%)", + oklch: "oklch(0.70,0.03,210)", + }, + { + scale: 500, + hex: "#648085", + rgb: "rgb(100,128,133)", + hsl: "hsl(189.3,14.2%,45.7%)", + oklch: "oklch(0.58,0.03,210)", + }, + { + scale: 600, + hex: "#4f676b", + rgb: "rgb(79,103,107)", + hsl: "hsl(189.3,15.1%,36.5%)", + oklch: "oklch(0.49,0.03,210)", + }, + { + scale: 700, + hex: "#3d5155", + rgb: "rgb(61,81,85)", + hsl: "hsl(189.3,15.9%,28.6%)", + oklch: "oklch(0.42,0.03,210)", + }, + { + scale: 800, + hex: "#2d3c3f", + rgb: "rgb(45,60,63)", + hsl: "hsl(189.3,17.2%,21.2%)", + oklch: "oklch(0.34,0.02,210)", + }, + { + scale: 900, + hex: "#1e2a2c", + rgb: "rgb(30,42,44)", + hsl: "hsl(189.3,19.2%,14.6%)", + oklch: "oklch(0.28,0.02,210)", + }, + { + scale: 950, + hex: "#0e1517", + rgb: "rgb(14,21,23)", + hsl: "hsl(189.3,25.3%,7.1%)", + oklch: "oklch(0.19,0.01,210)", + }, + ], + taupe: [ + { + scale: 50, + hex: "#fbfaf9", + rgb: "rgb(251,250,249)", + hsl: "hsl(34,21.3%,97.9%)", + oklch: "oklch(0.98,0.00,75)", + }, + { + scale: 100, + hex: "#f5f3f0", + rgb: "rgb(245,243,240)", + hsl: "hsl(34,22.7%,95.1%)", + oklch: "oklch(0.96,0.01,75)", + }, + { + scale: 200, + hex: "#e7e2dc", + rgb: "rgb(231,226,220)", + hsl: "hsl(34.1,18.7%,88.4%)", + oklch: "oklch(0.92,0.01,75)", + }, + { + scale: 300, + hex: "#d3cbc0", + rgb: "rgb(211,203,192)", + hsl: "hsl(34.1,18.3%,79%)", + oklch: "oklch(0.84,0.02,75)", + }, + { + scale: 400, + hex: "#aa9e8d", + rgb: "rgb(170,158,141)", + hsl: "hsl(34.2,14.8%,61.1%)", + oklch: "oklch(0.70,0.03,75)", + }, + { + scale: 500, + hex: "#867865", + rgb: "rgb(134,120,101)", + hsl: "hsl(34.3,14.1%,46.1%)", + oklch: "oklch(0.58,0.03,75)", + }, + { + scale: 600, + hex: "#6c6050", + rgb: "rgb(108,96,80)", + hsl: "hsl(34.3,14.9%,36.8%)", + oklch: "oklch(0.49,0.03,75)", + }, + { + scale: 700, + hex: "#554b3e", + rgb: "rgb(85,75,62)", + hsl: "hsl(34.3,15.7%,28.9%)", + oklch: "oklch(0.42,0.03,75)", + }, + { + scale: 800, + hex: "#40382d", + rgb: "rgb(64,56,45)", + hsl: "hsl(34.3,17%,21.4%)", + oklch: "oklch(0.34,0.02,75)", + }, + { + scale: 900, + hex: "#2c271f", + rgb: "rgb(44,39,31)", + hsl: "hsl(34.3,17.7%,14.8%)", + oklch: "oklch(0.28,0.02,75)", + }, + { + scale: 950, + hex: "#17130e", + rgb: "rgb(23,19,14)", + hsl: "hsl(34.4,24.8%,7.2%)", + oklch: "oklch(0.19,0.01,75)", + }, + ], red: [ { scale: 50, From 74c4c7508b7f2902d38b3bd9dcacbac750bf6be7 Mon Sep 17 00:00:00 2001 From: shadcn Date: Mon, 16 Mar 2026 13:29:23 +0400 Subject: [PATCH 11/12] docs: review all docs (#10058) * docs: review all docs * fix Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * docs(spinner): reintroduce data-icon attribute guidance in radix spinner docs (#10059) * Initial plan * docs: add data-icon attribute instructions to radix/spinner.mdx button and badge sections Co-authored-by: shadcn <124599+shadcn@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: shadcn <124599+shadcn@users.noreply.github.com> --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> --- apps/v4/content/docs/(root)/figma.mdx | 2 +- apps/v4/content/docs/(root)/index.mdx | 2 +- apps/v4/content/docs/(root)/new.mdx | 2 +- apps/v4/content/docs/(root)/react-19.mdx | 2 +- apps/v4/content/docs/(root)/tailwind-v4.mdx | 4 ++-- .../content/docs/changelog/2024-03-blocks.mdx | 2 +- .../docs/changelog/2024-03-breadcrumb-otp.mdx | 2 +- .../changelog/2024-08-npx-shadcn-init.mdx | 8 ++++---- .../changelog/2025-04-cross-framework.mdx | 6 +++--- .../v4/content/docs/changelog/2025-04-mcp.mdx | 2 +- .../docs/changelog/2025-04-shadcn-2-5.mdx | 2 +- .../docs/changelog/2025-06-radix-ui.mdx | 2 +- .../docs/changelog/2025-08-cli-3-mcp.mdx | 6 +++--- .../docs/changelog/2025-09-registry-index.mdx | 2 +- .../docs/changelog/2025-10-new-components.mdx | 4 ++-- .../docs/changelog/2025-12-shadcn-create.mdx | 2 +- .../content/docs/changelog/2026-03-cli-v4.mdx | 2 +- .../docs/components/base/alert-dialog.mdx | 2 +- .../content/docs/components/base/button.mdx | 2 +- .../content/docs/components/base/carousel.mdx | 4 ++-- .../v4/content/docs/components/base/chart.mdx | 2 +- .../content/docs/components/base/combobox.mdx | 4 ++-- .../docs/components/base/data-table.mdx | 6 +++--- .../docs/components/base/dropdown-menu.mdx | 2 +- .../docs/components/base/input-otp.mdx | 2 +- .../docs/components/base/scroll-area.mdx | 2 +- .../content/docs/components/base/sonner.mdx | 4 ++-- .../content/docs/components/base/spinner.mdx | 4 ++-- .../docs/components/base/typography.mdx | 2 +- .../docs/components/radix/alert-dialog.mdx | 2 +- .../content/docs/components/radix/button.mdx | 2 +- .../docs/components/radix/carousel.mdx | 2 +- .../content/docs/components/radix/chart.mdx | 2 +- .../docs/components/radix/combobox.mdx | 4 ++-- .../docs/components/radix/data-table.mdx | 6 +++--- .../docs/components/radix/dropdown-menu.mdx | 2 +- .../docs/components/radix/input-otp.mdx | 2 +- .../docs/components/radix/scroll-area.mdx | 2 +- .../content/docs/components/radix/spinner.mdx | 4 ++-- .../docs/components/radix/typography.mdx | 2 +- apps/v4/content/docs/dark-mode/next.mdx | 2 +- apps/v4/content/docs/dark-mode/remix.mdx | 4 ++-- apps/v4/content/docs/dark-mode/vite.mdx | 2 +- apps/v4/content/docs/forms/next.mdx | 2 +- .../v4/content/docs/forms/react-hook-form.mdx | 4 ++-- apps/v4/content/docs/forms/tanstack-form.mdx | 2 +- apps/v4/content/docs/installation/astro.mdx | 4 ++-- apps/v4/content/docs/installation/gatsby.mdx | 4 ++-- apps/v4/content/docs/installation/laravel.mdx | 4 ++-- apps/v4/content/docs/installation/next.mdx | 2 +- apps/v4/content/docs/installation/remix.mdx | 2 +- apps/v4/content/docs/installation/vite.mdx | 4 ++-- apps/v4/content/docs/registry/examples.mdx | 20 +++++++++---------- apps/v4/content/docs/registry/faq.mdx | 2 +- apps/v4/content/docs/registry/open-in-v0.mdx | 2 +- .../content/docs/registry/registry-index.mdx | 1 - 56 files changed, 89 insertions(+), 90 deletions(-) diff --git a/apps/v4/content/docs/(root)/figma.mdx b/apps/v4/content/docs/(root)/figma.mdx index 5884181802..0ce70c92e8 100644 --- a/apps/v4/content/docs/(root)/figma.mdx +++ b/apps/v4/content/docs/(root)/figma.mdx @@ -16,7 +16,7 @@ description: Every component recreated in Figma. With customizable props, typogr ## Paid -- [shadcn/ui kit](https://shadcndesign.com) by [ Matt Wierzbicki](https://x.com/matsugfx) - A premium, always up-to-date UI kit for Figma - shadcn/ui compatible and optimized for smooth design-to-dev handoff. +- [shadcn/ui kit](https://shadcndesign.com) by [Matt Wierzbicki](https://x.com/matsugfx) - A premium, always up-to-date UI kit for Figma - shadcn/ui compatible and optimized for smooth design-to-dev handoff. - [Shadcraft UI Kit](https://shadcraft.com) - The most advanced shadcn-compatible kit with instant theming via [tweakcn](https://tweakcn.com), a pro library of components and templates, and complete coverage of shadcn components and blocks. - [shadcn/studio UI Kit](https://shadcnstudio.com/figma) - Accelerate design & development with a shadcn/ui compatible Figma kit with updated components, 550+ blocks, 10+ templates, 20+ themes, and an AI tool that converts designs into shadcn/ui code. - [Shadcnblocks.com](https://www.shadcnblocks.com) - A Premium Shadcn Figma UI Kit with components, 500+ pro blocks, shadcn theme variables, light/dark mode and Figma MCP ready. diff --git a/apps/v4/content/docs/(root)/index.mdx b/apps/v4/content/docs/(root)/index.mdx index b35634805e..16c70a9e01 100644 --- a/apps/v4/content/docs/(root)/index.mdx +++ b/apps/v4/content/docs/(root)/index.mdx @@ -27,7 +27,7 @@ shadcn/ui hands you the actual component code. You have full control to customiz _In a typical library, if you need to change a button’s behavior, you have to override styles or wrap the component. With shadcn/ui, you simply edit the button code directly._ - + How do I pull upstream updates in an Open Code approach? diff --git a/apps/v4/content/docs/(root)/new.mdx b/apps/v4/content/docs/(root)/new.mdx index 24efec1b32..be1a42797c 100644 --- a/apps/v4/content/docs/(root)/new.mdx +++ b/apps/v4/content/docs/(root)/new.mdx @@ -3,7 +3,7 @@ title: Your project is ready! description: You've created a new project with shadcn/ui. --- -Here's a few things you can do to get started building with shadcn/ui. +Here are a few things you can do to get started building with shadcn/ui. ## Add Components diff --git a/apps/v4/content/docs/(root)/react-19.mdx b/apps/v4/content/docs/(root)/react-19.mdx index 5d40383d73..832b0de7c8 100644 --- a/apps/v4/content/docs/(root)/react-19.mdx +++ b/apps/v4/content/docs/(root)/react-19.mdx @@ -121,7 +121,7 @@ The process for adding components is the same as above. Select a flag to resolve ## Upgrade Status -To make it easy for you track the progress of the upgrade, I've created a table below with React 19 support status for the shadcn/ui dependencies. +To make it easy for you to track the progress of the upgrade, here is a table with the React 19 support status for the shadcn/ui dependencies. - ✅ - Works with React 19 using npm, pnpm, and bun. - 🚧 - Works with React 19 using pnpm and bun. Requires flag for npm. PR is in progress. diff --git a/apps/v4/content/docs/(root)/tailwind-v4.mdx b/apps/v4/content/docs/(root)/tailwind-v4.mdx index 5b4bfc9544..0f35dff8d2 100644 --- a/apps/v4/content/docs/(root)/tailwind-v4.mdx +++ b/apps/v4/content/docs/(root)/tailwind-v4.mdx @@ -193,7 +193,7 @@ Here's how you do it: } ``` -This change makes it much simpler to access your theme variables in both utility classes and outside of CSS for eg. using color values in JavaScript. +This change makes it much simpler to access your theme variables in both utility classes and outside of CSS, e.g. using color values in JavaScript. ### 3. Update colors for charts @@ -281,7 +281,7 @@ function AccordionItem({ We've deprecated `tailwindcss-animate` in favor of `tw-animate-css`. -New project will have `tw-animate-css` installed by default. +New projects will have `tw-animate-css` installed by default. For existing projects, follow the steps below to migrate. diff --git a/apps/v4/content/docs/changelog/2024-03-blocks.mdx b/apps/v4/content/docs/changelog/2024-03-blocks.mdx index 6cd765ca7d..10d475b211 100644 --- a/apps/v4/content/docs/changelog/2024-03-blocks.mdx +++ b/apps/v4/content/docs/changelog/2024-03-blocks.mdx @@ -6,7 +6,7 @@ date: 2024-03-22 One of the most requested features since launch has been layouts: admin dashboards with sidebar, marketing page sections, cards and more. -**Today, we're launching [**Blocks**](/blocks)**. +**Today, we're launching [Blocks](/blocks).** Lift Mode diff --git a/apps/v4/content/docs/changelog/2025-04-shadcn-2-5.mdx b/apps/v4/content/docs/changelog/2025-04-shadcn-2-5.mdx index 86af7f5fdb..4292893e55 100644 --- a/apps/v4/content/docs/changelog/2025-04-shadcn-2-5.mdx +++ b/apps/v4/content/docs/changelog/2025-04-shadcn-2-5.mdx @@ -1,5 +1,5 @@ --- -title: March 2025 - shadcn 2.5.0 +title: April 2025 - shadcn 2.5.0 description: Resolve anywhere - registries can now place files anywhere in an app. date: 2025-04-26 --- diff --git a/apps/v4/content/docs/changelog/2025-06-radix-ui.mdx b/apps/v4/content/docs/changelog/2025-06-radix-ui.mdx index 235b371eb4..b8fd675fef 100644 --- a/apps/v4/content/docs/changelog/2025-06-radix-ui.mdx +++ b/apps/v4/content/docs/changelog/2025-06-radix-ui.mdx @@ -13,7 +13,7 @@ npx shadcn@latest migrate radix It will automatically update all imports in your `ui` components and install `radix-ui` as a dependency. ```diff showLineNumbers title="components/ui/alert-dialog.tsx" -- import * as AlertDialogPrimitive from "@radix-ui/react-dialog" +- import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog" + import { AlertDialog as AlertDialogPrimitive } from "radix-ui" ``` diff --git a/apps/v4/content/docs/changelog/2025-08-cli-3-mcp.mdx b/apps/v4/content/docs/changelog/2025-08-cli-3-mcp.mdx index f559654668..5c2946b25e 100644 --- a/apps/v4/content/docs/changelog/2025-08-cli-3-mcp.mdx +++ b/apps/v4/content/docs/changelog/2025-08-cli-3-mcp.mdx @@ -91,7 +91,7 @@ Need to keep your components private? We've got you covered. Configure authentic Your private components stay private. Perfect for enterprise teams with proprietary UI libraries. -We support all major authentication methods: basic auth, bearer token, api key query params and custom headers. +We support all major authentication methods: basic auth, bearer token, API key query params and custom headers. See the [authentication docs](/docs/registry/authentication) for more details. @@ -125,7 +125,7 @@ Preview components before installing them. Search across multiple registries. Se src="/images/mcp.jpeg" width="1432" height="1050" - alt="Lift Mode" + alt="MCP Server" className="mt-6 w-full overflow-hidden rounded-lg border" /> @@ -175,7 +175,7 @@ Missing environment variables? The CLI tells you exactly what's needed: Registry "@private" requires the following environment variables: • REGISTRY_TOKEN -Set the required environment variables to your .env or .env.local file. +Set the required environment variables in your .env or .env.local file. ``` Registry authors can provide custom error messages in their responses to help users and AI agents understand and fix issues quickly. diff --git a/apps/v4/content/docs/changelog/2025-09-registry-index.mdx b/apps/v4/content/docs/changelog/2025-09-registry-index.mdx index 32885f8cd3..480f374050 100644 --- a/apps/v4/content/docs/changelog/2025-09-registry-index.mdx +++ b/apps/v4/content/docs/changelog/2025-09-registry-index.mdx @@ -6,7 +6,7 @@ date: 2025-09-02 We've created an index of open source registries that you can install items from. -You can search, view and add items from the registry index without configuring the `.components.json` file. +You can search, view and add items from the registry index without configuring the `components.json` file. They'll be automatically added to your `components.json` file for you. diff --git a/apps/v4/content/docs/changelog/2025-10-new-components.mdx b/apps/v4/content/docs/changelog/2025-10-new-components.mdx index cba759ba92..1e3745f023 100644 --- a/apps/v4/content/docs/changelog/2025-10-new-components.mdx +++ b/apps/v4/content/docs/changelog/2025-10-new-components.mdx @@ -173,7 +173,7 @@ You can also add buttons to the input group. className="[&_.preview]:h-[300px] [&_pre]:h-[300px]!" /> -Or text, labels, tooltips,... +Or text, labels, tooltips, ... -Wait here's more. Wrap your fields in `FieldLabel` to create a selectable field group. Really easy. And it looks great. +Wait, here's more. Wrap your fields in `FieldLabel` to create a selectable field group. Really easy. And it looks great. -### Link +### As Link You can use the `buttonVariants` helper to make a link look like a button. diff --git a/apps/v4/content/docs/components/base/carousel.mdx b/apps/v4/content/docs/components/base/carousel.mdx index 1c07e3a4b7..a9a77c3b0a 100644 --- a/apps/v4/content/docs/components/base/carousel.mdx +++ b/apps/v4/content/docs/components/base/carousel.mdx @@ -182,7 +182,7 @@ You can pass options to the carousel using the `opts` prop. See the [Embla Carou ## API -Use a state and the `setApi` props to get an instance of the carousel API. +Use a state and the `setApi` prop to get an instance of the carousel API. @@ -240,7 +240,7 @@ Use the `disabled` prop to disable the combobox. ### Auto Highlight -Use the `autoHighlight` prop automatically highlight the first item on filter. +Use the `autoHighlight` prop to automatically highlight the first item on filter. diff --git a/apps/v4/content/docs/components/base/data-table.mdx b/apps/v4/content/docs/components/base/data-table.mdx index 03a90f65fc..4a02b4a496 100644 --- a/apps/v4/content/docs/components/base/data-table.mdx +++ b/apps/v4/content/docs/components/base/data-table.mdx @@ -316,13 +316,13 @@ You can use the same approach to format other cells and headers. ## Row Actions -Let's add row actions to our table. We'll use a `` component for this. +Let's add row actions to our table. We'll use a `` component for this. ### Update columns definition -Update our columns definition to add a new `actions` column. The `actions` cell returns a `` component. +Update our columns definition to add a new `actions` column. The `actions` cell returns a `` component. ```tsx showLineNumbers title="app/payments/columns.tsx" {4,6-14,18-45} "use client" @@ -472,7 +472,7 @@ Let's make the email column sortable. ### Update `` -```tsx showLineNumbers title="app/payments/data-table.tsx" showLineNumbers {3,6,10,18,25-29} +```tsx showLineNumbers title="app/payments/data-table.tsx" {3,6,10,18,25-29} "use client" import * as React from "react" diff --git a/apps/v4/content/docs/components/base/dropdown-menu.mdx b/apps/v4/content/docs/components/base/dropdown-menu.mdx index b63bfc10bd..3913e0518c 100644 --- a/apps/v4/content/docs/components/base/dropdown-menu.mdx +++ b/apps/v4/content/docs/components/base/dropdown-menu.mdx @@ -82,8 +82,8 @@ import { My Account Profile Billing - + Team Subscription diff --git a/apps/v4/content/docs/components/base/input-otp.mdx b/apps/v4/content/docs/components/base/input-otp.mdx index f64f7d6666..3b23441422 100644 --- a/apps/v4/content/docs/components/base/input-otp.mdx +++ b/apps/v4/content/docs/components/base/input-otp.mdx @@ -1,6 +1,6 @@ --- title: Input OTP -description: Accessible one-time password component with copy paste functionality. +description: Accessible one-time password component with copy-paste functionality. base: base component: true links: diff --git a/apps/v4/content/docs/components/base/scroll-area.mdx b/apps/v4/content/docs/components/base/scroll-area.mdx index 580fcdb46c..3d961ff9a9 100644 --- a/apps/v4/content/docs/components/base/scroll-area.mdx +++ b/apps/v4/content/docs/components/base/scroll-area.mdx @@ -59,7 +59,7 @@ npm install @base-ui/react ## Usage ```tsx showLineNumbers -import { ScrollArea } from "@/components/ui/scroll-area" +import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area" ``` ```tsx showLineNumbers diff --git a/apps/v4/content/docs/components/base/sonner.mdx b/apps/v4/content/docs/components/base/sonner.mdx index aaa65a4e6a..02cd129e8d 100644 --- a/apps/v4/content/docs/components/base/sonner.mdx +++ b/apps/v4/content/docs/components/base/sonner.mdx @@ -31,7 +31,7 @@ Sonner is built and maintained by [emilkowalski](https://twitter.com/emilkowalsk npx shadcn@latest add sonner ``` -Add the Toaster component +Add the Toaster component. ```tsx title="app/layout.tsx" {1,9} showLineNumbers import { Toaster } from "@/components/ui/sonner" @@ -71,7 +71,7 @@ npm install sonner next-themes styleName="base-nova" /> -Add the Toaster component +Add the Toaster component. ```tsx showLineNumbers title="app/layout.tsx" {1,8} import { Toaster } from "@/components/ui/sonner" diff --git a/apps/v4/content/docs/components/base/spinner.mdx b/apps/v4/content/docs/components/base/spinner.mdx index d209690563..8146e22ce8 100644 --- a/apps/v4/content/docs/components/base/spinner.mdx +++ b/apps/v4/content/docs/components/base/spinner.mdx @@ -88,13 +88,13 @@ Use the `size-*` utility class to change the size of the spinner. ### Button -Add a spinner to a button to indicate a loading state. Remember to use the `data-icon="inline-start"` prop to add the spinner to the start of the button and the `data-icon="inline-end"` prop to add the spinner to the end of the button. +Add a spinner to a button to indicate a loading state. Place the `` before the label with `data-icon="inline-start"` for a start position, or after the label with `data-icon="inline-end"` for an end position. ### Badge -Add a spinner to a badge to indicate a loading state. Remember to use the `data-icon="inline-start"` prop to add the spinner to the start of the badge and the `data-icon="inline-end"` prop to add the spinner to the end of the badge. +Add a spinner to a badge to indicate a loading state. Place the `` before the label with `data-icon="inline-start"` for a start position, or after the label with `data-icon="inline-end"` for an end position. diff --git a/apps/v4/content/docs/components/base/typography.mdx b/apps/v4/content/docs/components/base/typography.mdx index 6d2eff786e..21953c1ed0 100644 --- a/apps/v4/content/docs/components/base/typography.mdx +++ b/apps/v4/content/docs/components/base/typography.mdx @@ -1,6 +1,6 @@ --- title: Typography -description: Styles for headings, paragraphs, lists...etc +description: Styles for headings, paragraphs, lists, etc. base: base component: true --- diff --git a/apps/v4/content/docs/components/radix/alert-dialog.mdx b/apps/v4/content/docs/components/radix/alert-dialog.mdx index b36577099b..425aa94937 100644 --- a/apps/v4/content/docs/components/radix/alert-dialog.mdx +++ b/apps/v4/content/docs/components/radix/alert-dialog.mdx @@ -161,7 +161,7 @@ To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl) ### size -Use the `size` props on the `AlertDialogContent` component to control the size of the alert dialog. It accepts the following values: +Use the `size` prop on the `AlertDialogContent` component to control the size of the alert dialog. It accepts the following values: | Prop | Type | Default | | ------ | ------------------- | ----------- | diff --git a/apps/v4/content/docs/components/radix/button.mdx b/apps/v4/content/docs/components/radix/button.mdx index 10d6fecdd2..263526b364 100644 --- a/apps/v4/content/docs/components/radix/button.mdx +++ b/apps/v4/content/docs/components/radix/button.mdx @@ -135,7 +135,7 @@ To create a button group, use the `ButtonGroup` component. See the [Button Group -### Link +### As Child You can use the `asChild` prop on ` diff --git a/apps/v4/content/docs/registry/examples.mdx b/apps/v4/content/docs/registry/examples.mdx index 66715513da..a537a4a505 100644 --- a/apps/v4/content/docs/registry/examples.mdx +++ b/apps/v4/content/docs/registry/examples.mdx @@ -44,7 +44,7 @@ The following registry item is a custom style that extends shadcn/ui. On `npx sh The following registry item is a custom style that doesn't extend shadcn/ui. See the `extends: none` field. -It can be used to create a new style from scratch i.e custom components, css vars, dependencies, etc. +It can be used to create a new style from scratch, i.e. custom components, css vars, dependencies, etc. On `npx shadcn add`, the following will: @@ -69,21 +69,21 @@ On `npx shadcn add`, the following will: ], "cssVars": { "theme": { - "font-sans": "Inter, sans-serif", - } + "font-sans": "Inter, sans-serif" + }, "light": { "main": "#88aaee", "bg": "#dfe5f2", "border": "#000", "text": "#000", - "ring": "#000", + "ring": "#000" }, "dark": { "main": "#88aaee", "bg": "#272933", "border": "#000", "text": "#e6e6e6", - "ring": "#fff", + "ring": "#fff" } } } @@ -147,7 +147,7 @@ The following style will init using shadcn/ui defaults and then add a custom `br ### Custom block -This blocks installs the `login-01` block from the shadcn/ui registry. +This block installs the `login-01` block from the shadcn/ui registry. ```json title="login-01.json" showLineNumbers { @@ -174,7 +174,7 @@ This blocks installs the `login-01` block from the shadcn/ui registry. ### Install a block and override primitives -You can install a block fromt the shadcn/ui registry and override the primitives using your custom ones. +You can install a block from the shadcn/ui registry and override the primitives using your custom ones. On `npx shadcn add`, the following will: @@ -877,7 +877,7 @@ Note: you need to define both `@keyframes` in css and `theme` in cssVars to use You can add environment variables using the `envVars` field. ```json title="example-item.json" showLineNumbers {5-9} -{» +{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "custom-item", "type": "registry:item", @@ -921,7 +921,7 @@ Here's an example of a registry item that installs custom Cursor rules for _pyth } ``` -Here's another example for installation custom ESLint config: +Here's another example for installing a custom ESLint config: ```json title=".eslintrc.json" showLineNumbers {9} { @@ -944,7 +944,7 @@ You can also have a universal item that installs multiple files: ```json title="my-custom-starter-template.json" showLineNumbers {9} { "$schema": "https://ui.shadcn.com/schema/registry-item.json", - "name": "my-custom-start-template", + "name": "my-custom-starter-template", "type": "registry:item", "dependencies": ["better-auth"], "files": [ diff --git a/apps/v4/content/docs/registry/faq.mdx b/apps/v4/content/docs/registry/faq.mdx index 2e1963caae..a59cae6f02 100644 --- a/apps/v4/content/docs/registry/faq.mdx +++ b/apps/v4/content/docs/registry/faq.mdx @@ -36,7 +36,7 @@ Here's an example of a complex component that installs a page, two components, a }, { "path": "registry/new-york/hello-world/lib/format-date.ts", - "type": "registry:utils" + "type": "registry:lib" }, { "path": "registry/new-york/hello-world/hello.config.ts", diff --git a/apps/v4/content/docs/registry/open-in-v0.mdx b/apps/v4/content/docs/registry/open-in-v0.mdx index 66ea29226a..c4416db364 100644 --- a/apps/v4/content/docs/registry/open-in-v0.mdx +++ b/apps/v4/content/docs/registry/open-in-v0.mdx @@ -18,7 +18,7 @@ See [Build your Open in v0 button](https://v0.dev/chat/button) for more informat Here's a simple example of how to add a `Open in v0` button to your site. -```jsx showLineNumbers +```tsx showLineNumbers import { Button } from "@/components/ui/button" export function OpenInV0Button({ url }: { url: string }) { diff --git a/apps/v4/content/docs/registry/registry-index.mdx b/apps/v4/content/docs/registry/registry-index.mdx index aae64f7834..ad55d2a19a 100644 --- a/apps/v4/content/docs/registry/registry-index.mdx +++ b/apps/v4/content/docs/registry/registry-index.mdx @@ -56,7 +56,6 @@ Here's an example of a valid registry: } ] } - } ] } ``` From dbe1fa76b393228c014ecaa9072adcfe67ab6ee7 Mon Sep 17 00:00:00 2001 From: shadcn Date: Mon, 16 Mar 2026 16:16:16 +0400 Subject: [PATCH 12/12] fix(tests): fix e2e sleep (#10061) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(tests): wait for registry readiness in global setup instead of per-test sleep The first e2e test was flaky on CI because `start-server-and-test` only checks that the root URL (http://localhost:4000) responds before running tests, not the /r registry endpoint. The existing 2-second hardcoded sleep in the first test was unreliable on slower CI runners. Move the readiness check into the vitest globalSetup so all tests wait for the registry /r endpoint to actually be reachable before any test starts. Co-Authored-By: Claude Sonnet 4.6 * fix(tests): fix race condition in global setup - poll correct URL and CLI binary Two issues caused the previous fix to fail: 1. Was polling `http://localhost:4000/r` which is a directory → always 404. Now polls `{REGISTRY_URL}/index.json`, a real static file that returns 200. 2. The v4 dev script (`pnpm --filter=shadcn build && pnpm icons:dev & next dev`) runs the shadcn CLI build in the background while next dev starts immediately. On fast CI runs start-server-and-test can detect the server as ready before the CLI binary (packages/shadcn/dist/index.js) has been built, causing the first test to fail when it tries to invoke the CLI. Now explicitly waits for the binary to exist before any test runs. Co-Authored-By: Claude Sonnet 4.6 * fix(tests): warm up /init route in global setup to prevent first-test timeout The CLI's first request during `shadcn init` hits the dynamic Next.js /init route. On a cold dev server this route takes ~1.8s to compile. Combined with the rest of what init does (pnpm install, file writes), this pushes the first test over the 30s CLI timeout on CI. Subsequent tests pass because the route is already warm. Polling /init in global setup ensures the route is compiled before any test runs, making the first test's CLI invocation as fast as all subsequent ones. Also replaced the /r/index.json poll (a static file that responds immediately and doesn't reflect real route readiness) with the actual /init route poll, which also naturally verifies the registry server is up. Co-Authored-By: Claude Sonnet 4.6 * fix(tests): warm up 404 route and increase default CLI timeout Two more issues found in CI logs: 1. The CLI requests font files that don't exist (e.g. /r/styles/new-york-v4/ font-geist.json), causing Next.js to compile /_not-found/page on the first 404 response. That compilation takes ~4-5s on a cold dev server and is another hidden cost on the first test. Now triggering a 404 in global setup so the not-found page is compiled before any test runs. 2. The default CLI timeout of 30s is too tight for CI. Even with the /init and 404 routes pre-warmed, pnpm install inside the fixture takes ~25s, leaving only ~5s of headroom. Increasing the default from 30s to 60s gives a comfortable buffer without masking real hangs. Co-Authored-By: Claude Sonnet 4.6 --------- Co-authored-by: Claude Sonnet 4.6 --- packages/tests/src/tests/init.test.ts | 3 -- packages/tests/src/utils/helpers.ts | 2 +- packages/tests/src/utils/setup.ts | 50 +++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/packages/tests/src/tests/init.test.ts b/packages/tests/src/tests/init.test.ts index 358063700b..8433838949 100644 --- a/packages/tests/src/tests/init.test.ts +++ b/packages/tests/src/tests/init.test.ts @@ -12,9 +12,6 @@ import { createRegistryServer } from "../utils/registry" describe("shadcn init - next-app", () => { it("should init with default configuration", async () => { - // Sleep for 1 second to avoid race condition with the registry server. - await new Promise((resolve) => setTimeout(resolve, 2000)) - const fixturePath = await createFixtureTestDirectory("next-app") await npxShadcn(fixturePath, ["init", "--defaults"]) diff --git a/packages/tests/src/utils/helpers.ts b/packages/tests/src/utils/helpers.ts index 31b0a10397..b6437e2dc5 100644 --- a/packages/tests/src/utils/helpers.ts +++ b/packages/tests/src/utils/helpers.ts @@ -47,7 +47,7 @@ export async function runCommand( }, input: options?.input, reject: false, - timeout: options?.timeout ?? 30000, + timeout: options?.timeout ?? 60000, }) const result = await childProcess diff --git a/packages/tests/src/utils/setup.ts b/packages/tests/src/utils/setup.ts index 98b3acf24c..6b14b85fb5 100644 --- a/packages/tests/src/utils/setup.ts +++ b/packages/tests/src/utils/setup.ts @@ -4,9 +4,59 @@ import { rimraf } from "rimraf" export const TEMP_DIR = path.join(__dirname, "../../temp") +const SHADCN_CLI_PATH = path.join(__dirname, "../../../shadcn/dist/index.js") + +async function waitForCondition( + label: string, + check: () => Promise, + timeoutMs = 60000 +) { + const deadline = Date.now() + timeoutMs + while (Date.now() < deadline) { + if (await check()) return + await new Promise((resolve) => setTimeout(resolve, 500)) + } + throw new Error(`Timed out waiting for: ${label} (${timeoutMs}ms)`) +} + export default async function setup() { await fs.ensureDir(TEMP_DIR) + // The v4 dev script runs `pnpm --filter=shadcn build` in the background + // while `next dev` starts immediately. On fast CI runs the server can be + // ready before the CLI binary is built, so we wait for it explicitly. + await waitForCondition("shadcn CLI binary", () => + fs.pathExists(SHADCN_CLI_PATH) + ) + + // The CLI's first request goes to the dynamic /init route. On a cold Next.js + // dev server, this route needs to be compiled on first access (~1.8s). That + // compilation time, on top of everything else init does, pushes the first + // test over the 30s CLI timeout. Warming up the route here ensures it is + // already compiled before any test starts. + const registryUrl = process.env.REGISTRY_URL || "http://localhost:4000/r" + const shadcnUrl = registryUrl.replace(/\/r\/?$/, "") + const initWarmupUrl = `${shadcnUrl}/init?base=base&style=nova&baseColor=neutral&theme=neutral&iconLibrary=lucide&font=geist&rtl=false&menuAccent=subtle&menuColor=default&radius=default&template=next` + + await waitForCondition("init route warm-up", async () => { + try { + const res = await fetch(initWarmupUrl) + return res.ok + } catch { + return false + } + }) + + // The CLI fetches registry paths that may not exist (e.g. font files), + // causing Next.js to compile the /_not-found/page route on first 404. + // That compilation takes ~4-5s and contributes to the first test timing + // out. Trigger one 404 here so the not-found page is pre-compiled. + try { + await fetch(`${shadcnUrl}/r/styles/new-york-v4/font-geist.json`) + } catch { + // Best effort — don't block setup if this fails. + } + return async () => { try { await rimraf(TEMP_DIR)