From 77f66d53577639a08f7345552f92a4e56f508b6a Mon Sep 17 00:00:00 2001 From: David King Roderos Date: Thu, 19 Feb 2026 14:08:31 +0800 Subject: [PATCH 1/9] Fix highlighted changes On the sorting section, I've included the closing brackets of state of useReactTable() on the highlighted changes --- apps/v4/content/docs/components/base/data-table.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/v4/content/docs/components/base/data-table.mdx b/apps/v4/content/docs/components/base/data-table.mdx index 4cbc976d34..23295d86e5 100644 --- a/apps/v4/content/docs/components/base/data-table.mdx +++ b/apps/v4/content/docs/components/base/data-table.mdx @@ -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-28} +```tsx showLineNumbers title="app/payments/data-table.tsx" showLineNumbers {3,6,10,18,25-29} "use client" import * as React from "react" From 01d5f034b9c1fb20d01f713bb04317811b22bcf7 Mon Sep 17 00:00:00 2001 From: Albert Asaftei Date: Fri, 20 Feb 2026 09:58:43 +0100 Subject: [PATCH 2/9] chore: modified pixelact-ui description --- apps/v4/public/r/registries.json | 2 +- apps/v4/registry/directory.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/v4/public/r/registries.json b/apps/v4/public/r/registries.json index a9502c3063..e67a174794 100644 --- a/apps/v4/public/r/registries.json +++ b/apps/v4/public/r/registries.json @@ -783,6 +783,6 @@ "name": "@pixelact-ui", "homepage": "https://pixelactui.com", "url": "https://pixelactui.com/r/{name}.json", - "description": "Playful pixel-art style components library built on top of shadcn" + "description": "Playful pixel art style components library built on top of shadcn. Perfect for retro style projects and games." } ] \ No newline at end of file diff --git a/apps/v4/registry/directory.json b/apps/v4/registry/directory.json index 6e0301329d..e2540e6685 100644 --- a/apps/v4/registry/directory.json +++ b/apps/v4/registry/directory.json @@ -913,7 +913,7 @@ "name": "@pixelact-ui", "homepage": "https://pixelactui.com", "url": "https://pixelactui.com/r/{name}.json", - "description": "Playful pixel-art style components library built on top of shadcn", + "description": "Playful pixel art style components library built on top of shadcn. Perfect for retro style projects and games.", "logo": "" } ] From fc79e821085b6566775537d5cd10a9021c743007 Mon Sep 17 00:00:00 2001 From: Ronny Badilla Date: Mon, 9 Feb 2026 10:11:17 -0600 Subject: [PATCH 3/9] feat(shadcn): add HTTP 410 (Gone) support to registry fetcher --- packages/shadcn/src/registry/errors.ts | 17 +++++++++++++++++ packages/shadcn/src/registry/fetcher.test.ts | 8 ++++++++ packages/shadcn/src/registry/fetcher.ts | 5 +++++ 3 files changed, 30 insertions(+) diff --git a/packages/shadcn/src/registry/errors.ts b/packages/shadcn/src/registry/errors.ts index fff5d4d309..42dd47fdbc 100644 --- a/packages/shadcn/src/registry/errors.ts +++ b/packages/shadcn/src/registry/errors.ts @@ -5,6 +5,7 @@ export const RegistryErrorCode = { // Network errors NETWORK_ERROR: "NETWORK_ERROR", NOT_FOUND: "NOT_FOUND", + GONE: "GONE", UNAUTHORIZED: "UNAUTHORIZED", FORBIDDEN: "FORBIDDEN", FETCH_ERROR: "FETCH_ERROR", @@ -90,6 +91,22 @@ export class RegistryNotFoundError extends RegistryError { } } +export class RegistryGoneError extends RegistryError { + constructor(public readonly url: string, cause?: unknown) { + const message = `The item at ${url} is no longer available. It may have been removed or expired.` + + super(message, { + code: RegistryErrorCode.GONE, + statusCode: 410, + cause, + context: { url }, + suggestion: + "This resource was previously available but has been permanently removed. Check if a newer version exists or contact the registry maintainer.", + }) + this.name = "RegistryGoneError" + } +} + export class RegistryUnauthorizedError extends RegistryError { constructor(public readonly url: string, cause?: unknown) { const message = `You are not authorized to access the item at ${url}. If this is a remote registry, you may need to authenticate.` diff --git a/packages/shadcn/src/registry/fetcher.test.ts b/packages/shadcn/src/registry/fetcher.test.ts index 7061e53e1a..0348db6c0b 100644 --- a/packages/shadcn/src/registry/fetcher.test.ts +++ b/packages/shadcn/src/registry/fetcher.test.ts @@ -2,6 +2,7 @@ import { REGISTRY_URL } from "@/src/registry/constants" import { RegistryFetchError, RegistryForbiddenError, + RegistryGoneError, RegistryNotFoundError, RegistryUnauthorizedError, } from "@/src/registry/errors" @@ -30,6 +31,9 @@ const server = setupServer( http.get(`${REGISTRY_URL}/forbidden.json`, () => { return new HttpResponse(null, { status: 403 }) }), + http.get(`${REGISTRY_URL}/gone.json`, () => { + return new HttpResponse(null, { status: 410 }) + }), http.get("https://external.com/component.json", () => { return HttpResponse.json({ name: "external", @@ -123,6 +127,10 @@ describe("fetchRegistry", () => { ) }) + it("should handle 410 errors", async () => { + await expect(fetchRegistry(["gone.json"])).rejects.toThrow(RegistryGoneError) + }) + it("should handle network errors", async () => { await expect(fetchRegistry(["error.json"])).rejects.toThrow() }) diff --git a/packages/shadcn/src/registry/fetcher.ts b/packages/shadcn/src/registry/fetcher.ts index 0e87aa50c7..e5df988310 100644 --- a/packages/shadcn/src/registry/fetcher.ts +++ b/packages/shadcn/src/registry/fetcher.ts @@ -6,6 +6,7 @@ import { getRegistryHeadersFromContext } from "@/src/registry/context" import { RegistryFetchError, RegistryForbiddenError, + RegistryGoneError, RegistryLocalFileError, RegistryNotFoundError, RegistryParseError, @@ -93,6 +94,10 @@ export async function fetchRegistry( throw new RegistryNotFoundError(url, messageFromServer) } + if (response.status === 410) { + throw new RegistryGoneError(url, messageFromServer) + } + if (response.status === 403) { throw new RegistryForbiddenError(url, messageFromServer) } From 40aca13fb0261e042aeb4a42921145a35b74812e Mon Sep 17 00:00:00 2001 From: shadcn Date: Sat, 21 Feb 2026 21:41:01 +0400 Subject: [PATCH 4/9] fix: handling of apply directive inside utility --- .../shadcn/src/utils/updaters/update-css.ts | 54 ++++++++- .../test/utils/updaters/update-css.test.ts | 108 ++++++++++++++++++ 2 files changed, 160 insertions(+), 2 deletions(-) diff --git a/packages/shadcn/src/utils/updaters/update-css.ts b/packages/shadcn/src/utils/updaters/update-css.ts index 37243225f5..b474891cfc 100644 --- a/packages/shadcn/src/utils/updaters/update-css.ts +++ b/packages/shadcn/src/utils/updaters/update-css.ts @@ -317,7 +317,7 @@ function updateCssPlugin(css: z.infer) { postcss.comment({ text: "---break---" }) ) - // Add declarations with their values preserved + // Add declarations with their values preserved. if (typeof properties === "object") { for (const [prop, value] of Object.entries(properties)) { if (typeof value === "string") { @@ -327,13 +327,38 @@ function updateCssPlugin(css: z.infer) { raws: { semicolon: true, before: "\n " }, }) atRule.append(decl) + } else if ( + prop.startsWith("@") && + typeof value === "object" && + value !== null && + Object.keys(value as Record).length === 0 + ) { + // Handle at-rules with no body (e.g., @apply). + const atRuleMatch = prop.match(/@([a-zA-Z-]+)\s*(.*)/) + if (atRuleMatch) { + const [, atRuleName, atRuleParams] = atRuleMatch + const existingAtRule = atRule.nodes?.find( + (node): node is AtRule => + node.type === "atrule" && + node.name === atRuleName && + node.params === atRuleParams + ) + if (!existingAtRule) { + const newAtRule = postcss.atRule({ + name: atRuleName, + params: atRuleParams, + raws: { semicolon: true, before: "\n " }, + }) + atRule.append(newAtRule) + } + } } else if (typeof value === "object") { processRule(atRule, prop, value) } } } } else { - // Update existing utility class + // Update existing utility class. if (typeof properties === "object") { for (const [prop, value] of Object.entries(properties)) { if (typeof value === "string") { @@ -351,6 +376,31 @@ function updateCssPlugin(css: z.infer) { existingDecl ? existingDecl.replaceWith(decl) : utilityAtRule.append(decl) + } else if ( + prop.startsWith("@") && + typeof value === "object" && + value !== null && + Object.keys(value as Record).length === 0 + ) { + // Handle at-rules with no body (e.g., @apply). + const atRuleMatch = prop.match(/@([a-zA-Z-]+)\s*(.*)/) + if (atRuleMatch) { + const [, atRuleName, atRuleParams] = atRuleMatch + const existingAtRule = utilityAtRule.nodes?.find( + (node): node is AtRule => + node.type === "atrule" && + node.name === atRuleName && + node.params === atRuleParams + ) + if (!existingAtRule) { + const newAtRule = postcss.atRule({ + name: atRuleName, + params: atRuleParams, + raws: { semicolon: true, before: "\n " }, + }) + utilityAtRule.append(newAtRule) + } + } } else if (typeof value === "object") { processRule(utilityAtRule, prop, value) } diff --git a/packages/shadcn/test/utils/updaters/update-css.test.ts b/packages/shadcn/test/utils/updaters/update-css.test.ts index 3470409922..e168f0dfeb 100644 --- a/packages/shadcn/test/utils/updaters/update-css.test.ts +++ b/packages/shadcn/test/utils/updaters/update-css.test.ts @@ -929,6 +929,114 @@ describe("transformCss", () => { `) }) + test("should handle @apply inside @utility", async () => { + const input = `@import "tailwindcss";` + + const result = await transformCss(input, { + "@utility custom-btn": { + "@apply px-4 py-2 rounded-md": {}, + }, + }) + + expect(result).toMatchInlineSnapshot(` + "@import "tailwindcss"; + + @utility custom-btn { + @apply px-4 py-2 rounded-md; + }" + `) + }) + + test("should handle @apply mixed with declarations inside @utility", async () => { + const input = `@import "tailwindcss";` + + const result = await transformCss(input, { + "@utility custom-card": { + "@apply bg-white shadow-md": {}, + "border-radius": "0.5rem", + }, + }) + + expect(result).toMatchInlineSnapshot(` + "@import "tailwindcss"; + + @utility custom-card { + @apply bg-white shadow-md; + border-radius: 0.5rem; + }" + `) + }) + + test("should handle multiple @apply inside @utility", async () => { + const input = `@import "tailwindcss";` + + const result = await transformCss(input, { + "@utility custom-input": { + "@apply border border-gray-300 rounded-md": {}, + "@apply focus:ring-2 focus:ring-blue-500": {}, + padding: "0.5rem", + }, + }) + + expect(result).toMatchInlineSnapshot(` + "@import "tailwindcss"; + + @utility custom-input { + @apply border border-gray-300 rounded-md; + @apply focus:ring-2 focus:ring-blue-500; + padding: 0.5rem; + }" + `) + }) + + test("should add @apply to existing @utility", async () => { + const input = `@import "tailwindcss"; + +@utility custom-alert { + font-size: 1rem; +}` + + const result = await transformCss(input, { + "@utility custom-alert": { + "@apply font-bold text-red-500": {}, + }, + }) + + expect(result).toMatchInlineSnapshot(` + "@import "tailwindcss"; + + @utility custom-alert { + font-size: 1rem; + @apply font-bold text-red-500; + }" + `) + }) + + test("should not duplicate @apply inside existing @utility", async () => { + const input = `@import "tailwindcss"; + +@utility custom-badge { + @apply inline-flex items-center; + font-size: 0.75rem; +}` + + const result = await transformCss(input, { + "@utility custom-badge": { + "@apply inline-flex items-center": {}, + "font-size": "0.875rem", + }, + }) + + expect(result).toMatchInlineSnapshot(` + "@import "tailwindcss"; + + @utility custom-badge { + @apply inline-flex items-center; + font-size: 0.875rem; + }" + `) + }) + test("should replace existing keyframes instead of duplicating", async () => { const input = `@import "tailwindcss"; From 82f03d0f1dd12efb5395a0b8689533588d778d0c Mon Sep 17 00:00:00 2001 From: shadcn Date: Sat, 21 Feb 2026 21:41:37 +0400 Subject: [PATCH 5/9] chore: changeset --- .changeset/ten-gifts-check.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/ten-gifts-check.md diff --git a/.changeset/ten-gifts-check.md b/.changeset/ten-gifts-check.md new file mode 100644 index 0000000000..c0cb133c59 --- /dev/null +++ b/.changeset/ten-gifts-check.md @@ -0,0 +1,5 @@ +--- +"shadcn": patch +--- + +handling of apply directive inside utility From a6ab998e5c15cc6975a87187378f1af7fb6ae553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Ch=C3=A1nh=20=C4=90=E1=BA=A1i?= Date: Sun, 22 Feb 2026 06:40:48 +0700 Subject: [PATCH 6/9] docs: add devDependencies section to registry-item-json.mdx --- .../content/docs/registry/registry-item-json.mdx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/apps/v4/content/docs/registry/registry-item-json.mdx b/apps/v4/content/docs/registry/registry-item-json.mdx index 8266b5d334..a9d82ae392 100644 --- a/apps/v4/content/docs/registry/registry-item-json.mdx +++ b/apps/v4/content/docs/registry/registry-item-json.mdx @@ -18,6 +18,7 @@ The `registry-item.json` schema is used to define your custom registry items. "https://example.com/r/foo" ], "dependencies": ["is-even@3.0.0", "motion"], + "devDependencies": ["tw-animate-css"], "files": [ { "path": "registry/new-york/hello-world/hello-world.tsx", @@ -144,6 +145,21 @@ Use `@version` to specify the version of your registry item. } ``` +### devDependencies + +The `devDependencies` property is used to specify the dev dependencies of your registry item. These are `npm` packages that are only needed during development. + +Use `@version` to specify the version of the package. + +```json title="registry-item.json" showLineNumbers +{ + "devDependencies": [ + "tw-animate-css", + "husky@^9.1.7" + ] +} +``` + ### registryDependencies Used for registry dependencies. Can be names, namespaced or URLs. From 805f73582f8ecbca91a2ea988b5723d61e2673cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Ch=C3=A1nh=20=C4=90=E1=BA=A1i?= Date: Sun, 22 Feb 2026 06:44:42 +0700 Subject: [PATCH 7/9] fix: update husky dependency to name@1.2.0 in registry-item-json.mdx --- apps/v4/content/docs/registry/registry-item-json.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/v4/content/docs/registry/registry-item-json.mdx b/apps/v4/content/docs/registry/registry-item-json.mdx index a9d82ae392..888bfaa258 100644 --- a/apps/v4/content/docs/registry/registry-item-json.mdx +++ b/apps/v4/content/docs/registry/registry-item-json.mdx @@ -155,7 +155,7 @@ Use `@version` to specify the version of the package. { "devDependencies": [ "tw-animate-css", - "husky@^9.1.7" + "name@1.2.0" ] } ``` From 474d461b1c269c662d0a3c2a364c0f5b0d13db95 Mon Sep 17 00:00:00 2001 From: harish-sundar_akto Date: Mon, 23 Feb 2026 13:30:54 +0530 Subject: [PATCH 8/9] feat(registry): add auth0 to registry directory --- 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 a9502c3063..f46af9c20b 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": "@auth0", + "homepage": "https://auth0.com", + "url": "https://ui.auth0.com/r/{name}.json", + "description": "Official Auth0 Universal Components for Web. Accelerate development with pre-built, embeddable UI for enterprise SSO, MFA, and organization management" + }, { "name": "@abui", "homepage": "https://abui.io", diff --git a/apps/v4/registry/directory.json b/apps/v4/registry/directory.json index 6e0301329d..44c7a0deb9 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": "@auth0", + "homepage": "https://auth0.com", + "url": "https://ui.auth0.com/r/{name}.json", + "description": "Official Auth0 Universal Components for Web. Accelerate development with pre-built, embeddable UI for enterprise SSO, MFA, and organization management", + "logo": "" + }, { "name": "@abui", "homepage": "https://abui.io", From 006dc8f9d00295ea7131521d91d889a0f44c3892 Mon Sep 17 00:00:00 2001 From: shadcn Date: Thu, 26 Feb 2026 23:42:59 +0400 Subject: [PATCH 9/9] feat: add shadcnuikit to registry --- 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 f68245ae70..a2f2eae219 100644 --- a/apps/v4/public/r/registries.json +++ b/apps/v4/public/r/registries.json @@ -533,6 +533,12 @@ "url": "https://shadcnui-blocks.com/r/{name}.json", "description": "A collection of premium, production-ready shadcn/ui blocks, components and templates." }, + { + "name": "@shadcnuikit", + "homepage": "https://shadcnuikit.com", + "url": "https://shadcnuikit.com/r/{name}.json", + "description": "Launch your projects faster with admin dashboards, website templates, components, blocks, and pre-built real-world examples." + }, { "name": "@shadcraft", "homepage": "https://free.shadcraft.com", diff --git a/apps/v4/registry/directory.json b/apps/v4/registry/directory.json index 9b4aa05ec3..f186ff7e2e 100644 --- a/apps/v4/registry/directory.json +++ b/apps/v4/registry/directory.json @@ -622,6 +622,13 @@ "description": "A collection of premium, production-ready shadcn/ui blocks, components and templates.", "logo": "" }, + { + "name": "@shadcnuikit", + "homepage": "https://shadcnuikit.com", + "url": "https://shadcnuikit.com/r/{name}.json", + "description": "Launch your projects faster with admin dashboards, website templates, components, blocks, and pre-built real-world examples.", + "logo": " " + }, { "name": "@shadcraft", "homepage": "https://free.shadcraft.com",