Compare commits

...

16 Commits

Author SHA1 Message Date
Claude
2139f1ac6c Use siteConfig instead of NEXT_PUBLIC_APP_URL for root layout metadata
The metadata in the root layout referenced process.env.NEXT_PUBLIC_APP_URL
with non-null assertions, but this env var is not guaranteed to be set
(only .env.example exists). This caused `new URL(undefined)` to throw
during SSR, resulting in a blank page on /create (and all other routes).

Replace all NEXT_PUBLIC_APP_URL references in metadata with siteConfig.url
and siteConfig.ogImage, which are already defined and used elsewhere in
the same metadata block.

https://claude.ai/code/session_01Ez3f6QxR3MxNq6YfAeqrcH
2026-03-18 15:44:56 +00:00
Claude
85cceaa7a9 Fix blank /create page by handling missing NEXT_PUBLIC_APP_URL env var
`new URL(process.env.NEXT_PUBLIC_APP_URL!)` in the root layout throws
"TypeError: Invalid URL" during SSR when the env var is not set (no .env
file, only .env.example exists), causing the entire page to return a 500
with an empty body. Fall back to http://localhost:4000 when the var is
undefined.

https://claude.ai/code/session_01Ez3f6QxR3MxNq6YfAeqrcH
2026-03-18 15:37:46 +00:00
shadcn
31dbc6fc91 Merge branch 'main' of github.com:shadcn-ui/ui 2026-03-18 10:53:27 +04:00
Victor Williams
8db2be8b09 feat: add @nexus-ui registry to public directory (#10067) 2026-03-18 10:11:15 +04:00
shadcn
a8bd00466a chore(templates): bump minor dependencies (#10076)
* fix: Update import path for Button component in react-router-app template

* chore(templates): bump minor dependencies

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Aboubakary Cissé <58236609+Aboubakary833@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 09:56:02 +04:00
shadcn
e78bb7b4f3 feat: move base picker to project form (#10077)
* feat: move base picker to project form

* fix: format
2026-03-17 09:55:37 +04:00
Aboubakary Cissé
acaa0953df fix: Update import path for Button component in react-router-app template (#10073) 2026-03-17 08:43:46 +04:00
shadcn
632e2c012e fix: update skill and add allowed-tools (#10075) 2026-03-17 08:26:13 +04:00
Danila Yudin
78f6a8b0f0 Add @sabraman ui registry (#10054)
* Add new UI component entry for @sabraman

* fix: update registries.json
2026-03-17 08:07:46 +04:00
Aboubakary Cissé
a9f997d00a fix: Update import path for Button component in react-router-app template 2026-03-17 02:25:06 +00:00
shadcn
dbe1fa76b3 fix(tests): fix e2e sleep (#10061)
* 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 <noreply@anthropic.com>

* 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 <noreply@anthropic.com>

* 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 <noreply@anthropic.com>

* 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 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 16:16:16 +04:00
shadcn
74c4c7508b 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>
2026-03-16 13:29:23 +04:00
atyb a.
4809da6f9c 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 <m@shadcn.com>
2026-03-16 08:36:19 +04:00
léo
7ffefce9e0 feat: add @0unlumen-ui registry (#9970)
* feat: add @0unlumen-ui registry

* fix: consistent registry name from @0unlumen-ui to @unlumen-ui
2026-03-15 15:21:09 +04:00
shadcn
6cad522930 chore: rebuild registry 2026-03-15 13:02:35 +04:00
shadcn
d683b05d7f chore: remove tooltip from mode switcher (#10047)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 12:58:00 +04:00
83 changed files with 764 additions and 284 deletions

View File

@@ -8,8 +8,6 @@ import {
CardHeader,
} from "@/examples/base/ui/card"
import { FieldGroup } from "@/examples/base/ui/field"
import { Separator } from "@/examples/base/ui/separator"
import { CardTitle } from "@/examples/radix/ui/card"
import { type RegistryItem } from "shadcn/schema"
import { useIsMobile } from "@/hooks/use-mobile"
@@ -23,7 +21,6 @@ import { FontPicker } from "@/app/(create)/components/font-picker"
import { IconLibraryPicker } from "@/app/(create)/components/icon-library-picker"
import { MainMenu } from "@/app/(create)/components/main-menu"
import { MenuColorPicker } from "@/app/(create)/components/menu-picker"
import { ProjectForm } from "@/app/(create)/components/project-form"
import { RadiusPicker } from "@/app/(create)/components/radius-picker"
import { RandomButton } from "@/app/(create)/components/random-button"
import { ResetDialog } from "@/app/(create)/components/reset-button"
@@ -58,7 +55,7 @@ export function Customizer({
</CardHeader>
<CardContent className="no-scrollbar min-h-0 flex-1 overflow-x-auto overflow-y-hidden md:overflow-y-auto">
<FieldGroup className="flex-row gap-2.5 py-px md:flex-col md:gap-3.25">
<BasePicker isMobile={isMobile} anchorRef={anchorRef} />
{isMobile && <BasePicker isMobile={isMobile} anchorRef={anchorRef} />}
<StylePicker
styles={STYLES}
isMobile={isMobile}

View File

@@ -104,7 +104,7 @@ export function MenuColorPicker({
<PickerTrigger>
<div className="flex flex-col justify-start text-left">
<div className="text-xs text-muted-foreground">Menu</div>
<div className="text-sm font-medium text-foreground">
<div className="line-clamp-1 text-sm font-medium text-foreground">
{currentMenu?.label}
</div>
</div>

View File

@@ -35,6 +35,7 @@ import { HugeiconsIcon } from "@hugeicons/react"
import { cn } from "@/lib/utils"
import { useConfig } from "@/hooks/use-config"
import { copyToClipboardWithMeta } from "@/components/copy-button"
import { BASES, type BaseName } from "@/registry/config"
import { usePresetCode } from "@/app/(create)/hooks/use-design-system"
import {
useDesignSystemSearchParams,
@@ -129,68 +130,74 @@ export function ProjectForm({
<DialogTrigger render={<Button className={cn(className)} />}>
Create Project
</DialogTrigger>
<DialogContent className="min-w-0 sm:max-w-sm">
<DialogContent className="no-scrollbar max-h-[calc(100svh-2rem)] overflow-y-auto sm:max-w-sm">
<DialogHeader>
<DialogTitle>Create Project</DialogTitle>
<DialogDescription>
Pick a template and configure your project. Available for all major
React frameworks.
Pick a template and configure your project.
</DialogDescription>
</DialogHeader>
<FieldGroup>
<Field>
<FieldLabel className="sr-only">Template</FieldLabel>
<TemplateGrid template={params.template} setParams={setParams} />
</Field>
<FieldSeparator />
<FieldSet>
<FieldLegend variant="label" className="sr-only">
Options
</FieldLegend>
<Field
orientation="horizontal"
data-disabled={hasMonorepo ? undefined : "true"}
>
<FieldLabel htmlFor="monorepo">
<span
className="size-4 text-foreground [&_svg]:size-4 [&_svg]:fill-current"
dangerouslySetInnerHTML={{
__html: TURBOREPO_LOGO,
}}
/>
Create a monorepo
</FieldLabel>
<Switch
id="monorepo"
checked={params.template?.endsWith("-monorepo") ?? false}
disabled={!hasMonorepo}
onCheckedChange={(checked) => {
const framework = getFramework(params.template ?? "next")
setParams({
template: getTemplateValue(
framework,
checked === true
) as typeof params.template,
})
}}
/>
<div>
<FieldGroup>
<Field>
<FieldLabel>Template</FieldLabel>
<TemplateGrid template={params.template} setParams={setParams} />
</Field>
<FieldSeparator />
<Field orientation="horizontal">
<FieldLabel htmlFor="rtl">
<HugeiconsIcon icon={Globe02Icon} className="size-4" />
Enable RTL support
</FieldLabel>
<Switch
id="rtl"
checked={params.rtl}
onCheckedChange={(checked) =>
setParams({ rtl: checked === true })
}
/>
<Field className="-mt-2">
<FieldLabel>Base</FieldLabel>
<BaseGrid base={params.base} setParams={setParams} />
</Field>
</FieldSet>
</FieldGroup>
<FieldSeparator />
<FieldSet>
<FieldLegend variant="label" className="sr-only">
Options
</FieldLegend>
<Field
orientation="horizontal"
data-disabled={hasMonorepo ? undefined : "true"}
>
<FieldLabel htmlFor="monorepo">
<span
className="size-4 text-foreground [&_svg]:size-4 [&_svg]:fill-current"
dangerouslySetInnerHTML={{
__html: TURBOREPO_LOGO,
}}
/>
Create a monorepo
</FieldLabel>
<Switch
id="monorepo"
checked={params.template?.endsWith("-monorepo") ?? false}
disabled={!hasMonorepo}
onCheckedChange={(checked) => {
const framework = getFramework(params.template ?? "next")
setParams({
template: getTemplateValue(
framework,
checked === true
) as typeof params.template,
})
}}
/>
</Field>
<FieldSeparator />
<Field orientation="horizontal">
<FieldLabel htmlFor="rtl">
<HugeiconsIcon icon={Globe02Icon} className="size-4" />
Enable RTL support
</FieldLabel>
<Switch
id="rtl"
checked={params.rtl}
onCheckedChange={(checked) =>
setParams({ rtl: checked === true })
}
/>
</Field>
</FieldSet>
</FieldGroup>
</div>
<DialogFooter className="min-w-0">
<div className="flex w-full min-w-0 flex-col gap-3">
<Tabs
@@ -310,3 +317,52 @@ const TemplateGrid = React.memo(function TemplateGrid({
</RadioGroup>
)
})
const BaseGrid = React.memo(function BaseGrid({
base,
setParams,
}: {
base: DesignSystemSearchParams["base"]
setParams: ReturnType<typeof useDesignSystemSearchParams>[1]
}) {
const handleBaseChange = React.useCallback(
(value: string) => {
setParams({ base: value as BaseName })
},
[setParams]
)
return (
<RadioGroup
value={base}
onValueChange={handleBaseChange}
aria-label="Base"
className="grid grid-cols-2 gap-2"
>
{BASES.map((item) => (
<FieldLabel
key={item.name}
htmlFor={`base-${item.name}`}
className="py-1"
>
<Field className="gap-0" orientation="horizontal">
<FieldContent className="flex flex-col items-center justify-center gap-2">
<div
className="size-6 text-foreground [&_svg]:size-6 *:[svg]:text-foreground!"
dangerouslySetInnerHTML={{
__html: item.meta?.logo ?? "",
}}
/>
<FieldTitle className="text-xs">{item.title}</FieldTitle>
</FieldContent>
<RadioGroupItem
value={item.name}
id={`base-${item.name}`}
className="sr-only absolute"
/>
</Field>
</FieldLabel>
))}
</RadioGroup>
)
})

View File

@@ -20,7 +20,7 @@ export const metadata: Metadata = {
default: siteConfig.name,
template: `%s - ${siteConfig.name}`,
},
metadataBase: new URL(process.env.NEXT_PUBLIC_APP_URL!),
metadataBase: new URL(siteConfig.url),
description: siteConfig.description,
keywords: ["Next.js", "React", "Tailwind CSS", "Components", "shadcn"],
authors: [
@@ -33,13 +33,13 @@ export const metadata: Metadata = {
openGraph: {
type: "website",
locale: "en_US",
url: process.env.NEXT_PUBLIC_APP_URL!,
url: siteConfig.url,
title: siteConfig.name,
description: siteConfig.description,
siteName: siteConfig.name,
images: [
{
url: `${process.env.NEXT_PUBLIC_APP_URL}/opengraph-image.png`,
url: siteConfig.ogImage,
width: 1200,
height: 630,
alt: siteConfig.name,
@@ -50,7 +50,7 @@ export const metadata: Metadata = {
card: "summary_large_image",
title: siteConfig.name,
description: siteConfig.description,
images: [`${process.env.NEXT_PUBLIC_APP_URL}/opengraph-image.png`],
images: [siteConfig.ogImage],
creator: "@shadcn",
},
icons: {

View File

@@ -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 (
<Tooltip>
<TooltipTrigger asChild>
<Button
variant={variant}
size="icon"
className={cn("group/toggle extend-touch-target size-8", className)}
onClick={toggleTheme}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="size-4.5"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" />
<path d="M12 3l0 18" />
<path d="M12 9l4.65 -4.65" />
<path d="M12 14.3l7.37 -7.37" />
<path d="M12 19.6l8.85 -8.85" />
</svg>
<span className="sr-only">Toggle theme</span>
</Button>
</TooltipTrigger>
<TooltipContent className="flex items-center gap-2 pr-1">
Toggle Mode <Kbd>D</Kbd>
</TooltipContent>
</Tooltip>
<Button
variant={variant}
size="icon"
className={cn("group/toggle extend-touch-target size-8", className)}
onClick={toggleTheme}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="size-4.5"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" />
<path d="M12 3l0 18" />
<path d="M12 9l4.65 -4.65" />
<path d="M12 14.3l7.37 -7.37" />
<path d="M12 19.6l8.85 -8.85" />
</svg>
<span className="sr-only">Toggle theme</span>
</Button>
)
}

View File

@@ -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.

View File

@@ -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 buttons behavior, you have to override styles or wrap the component. With shadcn/ui, you simply edit the button code directly._
<Accordion collapsible>
<Accordion type="single" collapsible>
<AccordionItem value="faq-1" className="border-none">
<AccordionTrigger>
How do I pull upstream updates in an Open Code approach?

View File

@@ -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

View File

@@ -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.

View File

@@ -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.

View File

@@ -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).**
<a href="/blocks">
<Image

View File

@@ -22,4 +22,4 @@ A fully featured input OTP component. It has support for numeric and alphanumeri
[Read the docs](/docs/components/input-otp)
If you have a [v0](https://v0.dev), the new components are available for generation.
If you have a [v0](https://v0.dev) account, the new components are available for generation.

View File

@@ -8,10 +8,10 @@ The new CLI is now available. It's a complete rewrite with a lot of new features
This is a major step towards distributing code that you and your LLMs can access and use.
1. First up, the cli now has support for all major React framework out of the box. Next.js, Remix, Vite and Laravel. And when you init into a new app, we update your existing Tailwind files instead of overriding.
2. A component now ship its own dependencies. Take the accordion for example, it can define its Tailwind keyframes. When you add it to your project, we'll update your tailwind.config.ts file accordingly.
1. First up, the CLI now has support for all major React frameworks out of the box. Next.js, Remix, Vite and Laravel. And when you init into a new app, we update your existing Tailwind files instead of overriding.
2. A component now ships its own dependencies. Take the accordion for example, it can define its Tailwind keyframes. When you add it to your project, we'll update your tailwind.config.ts file accordingly.
3. You can also install remote components using url. `npx shadcn add https://acme.com/registry/navbar.json`.
4. We have also improve the init command. It does framework detection and can even init a brand new Next.js app in one command. `npx shadcn init`.
4. We have also improved the init command. It does framework detection and can even init a brand new Next.js app in one command. `npx shadcn init`.
5. We have created a new schema that you can use to ship your own component registry. And since it has support for urls, you can even use it to distribute private components.
6. And a few more updates like better error handling and monorepo support.
@@ -42,4 +42,4 @@ To update an existing project to use the new CLI, update your `components.json`
}
```
If you're using a different import alias prefix eg `~`, replace `@` with your prefix.
If you're using a different import alias prefix, e.g. `~`, replace `@` with your prefix.

View File

@@ -1,9 +1,9 @@
---
title: March 2025 - Cross-framework Route Support
description: The shadcn CLI can now auto-detect your framework and adapts routes for you.
title: April 2025 - Cross-framework Route Support
description: The shadcn CLI can now auto-detect your framework and adapt routes for you.
date: 2025-04-09
---
The shadcn CLI can now auto-detect your framework and adapts routes for you.
The shadcn CLI can now auto-detect your framework and adapt routes for you.
Works with all frameworks including Laravel, Vite and React Router.

View File

@@ -10,7 +10,7 @@ We're working on zero-config MCP support for shadcn/ui registry. One command `np
src="/images/mcp.jpeg"
width="1432"
height="1050"
alt="Lift Mode"
alt="MCP Server"
className="mt-6 w-full overflow-hidden rounded-lg border"
/>

View File

@@ -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
---

View File

@@ -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"
```

View File

@@ -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.

View File

@@ -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.

View File

@@ -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, ...
<ComponentPreview
name="input-group-text"
@@ -266,7 +266,7 @@ between vertical and horizontal layouts based on container width. Done.
className="[&_.preview]:h-[600px] [&_pre]:h-[600px]!"
/>
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.
<ComponentPreview
name="field-choice-card"

View File

@@ -14,7 +14,7 @@ Today, we're changing that: **npx shadcn create**.
Customize Everything. Pick your component library, icons, base color, theme, fonts and create your own version of shadcn/ui.
We're starting with **5 new visual styles,** designed to help your UI actually feel like _your_ UI.
We're starting with **5 new visual styles**, designed to help your UI actually feel like _your_ UI.
- **Vega** The classic shadcn/ui look.
- **Nova** Reduced padding and margins for compact layouts.

View File

@@ -34,7 +34,7 @@ Use it to scaffold projects from custom config, share with your team or publish
## Switching presets
When you're working on a new app, it can take a few tries to find something you like so we've made switching presets really easy. Run init --preset in your app, and the cli will take care of reconfiguring everything including your components.
When you're working on a new app, it can take a few tries to find something you like so we've made switching presets really easy. Run `init --preset` in your app, and the CLI will take care of reconfiguring everything, including your components.
```bash
npx shadcn@latest init --preset ad3qkJ7

View File

@@ -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 |
| ------ | ------------------- | ----------- |

View File

@@ -135,7 +135,7 @@ To create a button group, use the `ButtonGroup` component. See the [Button Group
<ComponentPreview styleName="base-nova" name="button-group-demo" />
### Link
### As Link
You can use the `buttonVariants` helper to make a link look like a button.

View File

@@ -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.
<ComponentPreview
styleName="base-nova"
@@ -319,4 +319,4 @@ The `direction` option accepts `"ltr"` or `"rtl"` and should match the `dir` pro
## API Reference
See the [Embla Carousel docs](https://www.embla-carousel.com/api/plugins/) for more information on props and plugins.
See the [Embla Carousel docs](https://www.embla-carousel.com/api/) for more information on props and plugins.

View File

@@ -384,7 +384,7 @@ Charts have built-in support for theming. You can use css variables (recommended
--chart-2: oklch(0.6 0.118 184.704);
}
.dark: {
.dark {
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
}

View File

@@ -222,7 +222,7 @@ Use `ComboboxGroup` and `ComboboxSeparator` to group items.
### Custom Items
You can render custom component inside `ComboboxItem`.
You can render a custom component inside `ComboboxItem`.
<ComponentPreview styleName="base-nova" name="combobox-custom" />
@@ -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.
<ComponentPreview styleName="base-nova" name="combobox-auto-highlight" />

View File

@@ -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 `<Dropdown />` component for this.
Let's add row actions to our table. We'll use a `<DropdownMenu />` component for this.
<Steps className="mb-0 pt-2">
### Update columns definition
Update our columns definition to add a new `actions` column. The `actions` cell returns a `<Dropdown />` component.
Update our columns definition to add a new `actions` column. The `actions` cell returns a `<DropdownMenu />` 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 `<DataTable>`
```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"

View File

@@ -82,8 +82,8 @@ import {
<DropdownMenuLabel>My Account</DropdownMenuLabel>
<DropdownMenuItem>Profile</DropdownMenuItem>
<DropdownMenuItem>Billing</DropdownMenuItem>
<DropdownMenuSeparator />
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem>Team</DropdownMenuItem>
<DropdownMenuItem>Subscription</DropdownMenuItem>

View File

@@ -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:

View File

@@ -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

View File

@@ -31,7 +31,7 @@ Sonner is built and maintained by [emilkowalski](https://twitter.com/emilkowalsk
npx shadcn@latest add sonner
```
<Step>Add the Toaster component</Step>
<Step>Add the Toaster component.</Step>
```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"
/>
<Step>Add the Toaster component</Step>
<Step>Add the Toaster component.</Step>
```tsx showLineNumbers title="app/layout.tsx" {1,8}
import { Toaster } from "@/components/ui/sonner"

View File

@@ -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 `<Spinner />` 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.
<ComponentPreview styleName="base-nova" name="spinner-button" />
### 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 `<Spinner />` 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.
<ComponentPreview styleName="base-nova" name="spinner-badge" />

View File

@@ -1,6 +1,6 @@
---
title: Typography
description: Styles for headings, paragraphs, lists...etc
description: Styles for headings, paragraphs, lists, etc.
base: base
component: true
---

View File

@@ -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 |
| ------ | ------------------- | ----------- |

View File

@@ -135,7 +135,7 @@ To create a button group, use the `ButtonGroup` component. See the [Button Group
<ComponentPreview styleName="radix-nova" name="button-group-demo" />
### Link
### As Child
You can use the `asChild` prop on `<Button />` to make another component look like a button. Here's an example of a link that looks like a button.

View File

@@ -319,4 +319,4 @@ The `direction` option accepts `"ltr"` or `"rtl"` and should match the `dir` pro
## API Reference
See the [Embla Carousel docs](https://www.embla-carousel.com/api/plugins/) for more information on props and plugins.
See the [Embla Carousel docs](https://www.embla-carousel.com/api/) for more information on props and plugins.

View File

@@ -384,7 +384,7 @@ Charts have built-in support for theming. You can use css variables (recommended
--chart-2: oklch(0.6 0.118 184.704);
}
.dark: {
.dark {
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
}

View File

@@ -222,7 +222,7 @@ Use `ComboboxGroup` and `ComboboxSeparator` to group items.
### Custom Items
You can render custom component inside `ComboboxItem`.
You can render a custom component inside `ComboboxItem`.
<ComponentPreview styleName="base-nova" name="combobox-custom" />
@@ -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.
<ComponentPreview styleName="base-nova" name="combobox-auto-highlight" />

View File

@@ -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 `<Dropdown />` component for this.
Let's add row actions to our table. We'll use a `<DropdownMenu />` component for this.
<Steps className="mb-0 pt-2">
### Update columns definition
Update our columns definition to add a new `actions` column. The `actions` cell returns a `<Dropdown />` component.
Update our columns definition to add a new `actions` column. The `actions` cell returns a `<DropdownMenu />` 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 `<DataTable>`
```tsx showLineNumbers title="app/payments/data-table.tsx" showLineNumbers {3,6,10,18,25-28}
```tsx showLineNumbers title="app/payments/data-table.tsx" {3,6,10,18,25-28}
"use client"
import * as React from "react"

View File

@@ -83,8 +83,8 @@ import {
<DropdownMenuItem>Profile</DropdownMenuItem>
<DropdownMenuItem>Billing</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuItem>Team</DropdownMenuItem>
<DropdownMenuItem>Subscription</DropdownMenuItem>
</DropdownMenuGroup>

View File

@@ -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: radix
component: true
links:

View File

@@ -59,7 +59,7 @@ npm install radix-ui
## Usage
```tsx showLineNumbers
import { ScrollArea } from "@/components/ui/scroll-area"
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area"
```
```tsx showLineNumbers

View File

@@ -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 `<Spinner />` 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.
<ComponentPreview styleName="radix-nova" name="spinner-button" />
### 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 `<Spinner />` 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.
<ComponentPreview styleName="radix-nova" name="spinner-badge" />

View File

@@ -1,6 +1,6 @@
---
title: Typography
description: Styles for headings, paragraphs, lists...etc
description: Styles for headings, paragraphs, lists, etc.
base: radix
component: true
---

View File

@@ -1,6 +1,6 @@
---
title: Next.js
description: Adding dark mode to your next app.
description: Adding dark mode to your Next.js app.
---
<Steps>

View File

@@ -1,6 +1,6 @@
---
title: Remix
description: Adding dark mode to your remix app.
description: Adding dark mode to your Remix app.
---
<Steps>
@@ -103,7 +103,7 @@ export function App() {
## Add an action route
Create a file in `/routes/action.set-theme.ts`. Ensure that you pass the filename to the ThemeProvider component. This route it's used to store the preferred theme in the session storage when the user changes it.
Create a file in `/routes/action.set-theme.ts`. Ensure that you pass the filename to the ThemeProvider component. This route is used to store the preferred theme in the session storage when the user changes it.
```tsx title="app/routes/action.set-theme.ts" showLineNumbers
import { createThemeAction } from "remix-themes"

View File

@@ -1,6 +1,6 @@
---
title: Vite
description: Adding dark mode to your vite app.
description: Adding dark mode to your Vite app.
---
## Create a theme provider

View File

@@ -28,7 +28,7 @@ This form leverages Next.js and React's built-in capabilities for form handling.
- Uses Next.js `<Form />` component for navigation and progressive enhancement.
- `<Field />` components for building accessible forms.
- `useActionState` for managing form state and errors.
- Handles loading states with pending prop.
- Handles loading states with the pending prop.
- Server Actions for handling form submissions.
- Server-side validation using Zod.

View File

@@ -66,7 +66,7 @@ Here's a basic example of a form using the `<Controller />` component from React
### Create a form schema
We'll start by defining the shape of our form using a Zod schema
We'll start by defining the shape of our form using a Zod schema.
<Callout icon={<InfoIcon />}>
**Note:** This example uses `zod v3` for schema validation, but you can
@@ -89,7 +89,7 @@ const formSchema = z.object({
})
```
### Setup the form
### Set up the form
Next, we'll use the `useForm` hook from React Hook Form to create our form instance. We'll also add the Zod resolver to validate the form data.

View File

@@ -106,7 +106,7 @@ const formSchema = z.object({
})
```
### Setup the form
### Set up the form
Use the `useForm` hook from TanStack Form to create your form instance with Zod validation.

View File

@@ -1,6 +1,6 @@
---
title: Astro
description: Install and configure shadcn/ui for Astro
description: Install and configure shadcn/ui for Astro.
---
<Callout className="mb-6 border-emerald-600 bg-emerald-100 dark:border-emerald-400 dark:bg-emerald-900">
@@ -46,7 +46,7 @@ import { Button } from "@/components/ui/button"
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="generator" content={Astro.generator} />
<title>Astro + TailwindCSS</title>
<title>Astro + Tailwind CSS</title>
</head>
<body>

View File

@@ -1,6 +1,6 @@
---
title: Gatsby
description: Install and configure Gatsby.
description: Install and configure shadcn/ui for Gatsby.
---
<Callout className="mb-6 border-blue-600 bg-blue-50 dark:border-blue-900 dark:bg-blue-950 [&_code]:bg-blue-100 dark:[&_code]:bg-blue-900">
@@ -78,7 +78,7 @@ export const onCreateWebpackConfig = ({ actions }) => {
### Run the CLI
Run the `shadcn` init command to setup your project:
Run the `shadcn` init command to set up your project:
```bash
npx shadcn@latest init

View File

@@ -1,6 +1,6 @@
---
title: Laravel
description: Install and configure shadcn/ui for Laravel
description: Install and configure shadcn/ui for Laravel.
---
<Callout className="mb-6 border-emerald-600 bg-emerald-100 dark:border-emerald-400 dark:bg-emerald-900">
@@ -13,7 +13,7 @@ description: Install and configure shadcn/ui for Laravel
### Create Project
Start by creating a new Laravel project with Inertia and React using the laravel installer:
Start by creating a new Laravel project with Inertia and React using the Laravel installer:
```bash
laravel new my-app --react

View File

@@ -13,7 +13,7 @@ description: Install and configure shadcn/ui for Next.js.
### Create Project
Run the `init` command to create a new Next.js project or to setup an existing one:
Run the `init` command to create a new Next.js project or to set up an existing one:
```bash
npx shadcn@latest init -t next

View File

@@ -21,7 +21,7 @@ npx create-remix@latest my-app
### Run the CLI
Run the `shadcn` init command to setup your project:
Run the `shadcn` init command to set up your project:
```bash
npx shadcn@latest init

View File

@@ -13,7 +13,7 @@ description: Install and configure shadcn/ui for Vite.
### Create Project
Run the `init` command to create a new Vite project or to setup an existing one:
Run the `init` command to create a new Vite project or to set up an existing one:
```bash
npx shadcn@latest init -t vite
@@ -38,7 +38,7 @@ The command above will add the `Button` component to your project. You can then
```tsx {1,6} showLineNumbers title="src/App.tsx"
import { Button } from "@/components/ui/button"
export default function Home() {
export default function App() {
return (
<div>
<Button>Click me</Button>

View File

@@ -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": [

View File

@@ -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",

View File

@@ -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 }) {

View File

@@ -56,7 +56,6 @@ Here's an example of a valid registry:
}
]
}
}
]
}
```

View File

@@ -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",
@@ -910,5 +916,17 @@
"homepage": "https://ui.flexnative.com",
"url": "https://ui.flexnative.com/r/{name}.json",
"description": "A collection of customizable UI blocks with interactive live previews"
},
{
"name": "@nexus-ui",
"homepage": "https://nexus-ui.dev",
"url": "https://nexus-ui.dev/r/{name}.json",
"description": "Open-source component library of composable, copy-paste primitives for building AI interfaces (chat, streaming, multimodal)"
},
{
"name": "@sabraman",
"homepage": "https://sabraman.ru/components",
"url": "https://sabraman.ru/r/{name}.json",
"description": "Legacy skeuomorphic UI components and blocks for shadcn."
}
]

File diff suppressed because one or more lines are too long

View File

@@ -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 <Card className=\"w-full max-w-md\">\n <CardHeader>\n <CardTitle>Bug Report</CardTitle>\n <CardDescription>\n Help us improve by reporting bugs you encounter.\n </CardDescription>\n </CardHeader>\n <CardContent>\n <Form action={formAction} id=\"bug-report-form\">\n <FieldGroup>\n <Field data-invalid={!!formState.errors?.title?.length}>\n <FieldLabel htmlFor=\"title\">Bug Title</FieldLabel>\n <Input\n id=\"title\"\n name=\"title\"\n defaultValue={formState.values.title}\n disabled={pending}\n aria-invalid={!!formState.errors?.title?.length}\n placeholder=\"Login button not working on mobile\"\n autoComplete=\"off\"\n />\n {formState.errors?.title && (\n <FieldError>{formState.errors.title[0]}</FieldError>\n )}\n </Field>\n <Field data-invalid={!!formState.errors?.description?.length}>\n <FieldLabel htmlFor=\"description\">Description</FieldLabel>\n <InputGroup>\n <InputGroupTextarea\n id=\"description\"\n name=\"description\"\n defaultValue={formState.values.description}\n placeholder=\"I'm having an issue with the login button on mobile.\"\n rows={6}\n className=\"min-h-24 resize-none\"\n disabled={pending}\n aria-invalid={!!formState.errors?.description?.length}\n onChange={(e) => setDescriptionLength(e.target.value.length)}\n />\n <InputGroupAddon align=\"block-end\">\n <InputGroupText className=\"tabular-nums\">\n {descriptionLength}/100 characters\n </InputGroupText>\n </InputGroupAddon>\n </InputGroup>\n <FieldDescription>\n Include steps to reproduce, expected behavior, and what actually\n happened.\n </FieldDescription>\n {formState.errors?.description && (\n <FieldError>{formState.errors.description[0]}</FieldError>\n )}\n </Field>\n </FieldGroup>\n </Form>\n </CardContent>\n <CardFooter>\n <Field orientation=\"horizontal\">\n <Button type=\"submit\" disabled={pending} form=\"bug-report-form\">\n {pending && <Spinner />}\n Submit\n </Button>\n </Field>\n </CardFooter>\n </Card>\n )\n}\n",
"type": "registry:example"
}
]
],
"type": "registry:example"
}

View File

@@ -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"],

View File

@@ -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,

File diff suppressed because one or more lines are too long

View File

@@ -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",

View File

@@ -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"])

View File

@@ -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

View File

@@ -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<boolean>,
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)

View File

@@ -2,6 +2,7 @@
name: shadcn
description: Manages shadcn components and projects — adding, searching, fixing, debugging, styling, and composing UI. Provides project context, component docs, and usage examples. Applies when working with shadcn/ui, component registries, presets, --preset codes, or any project with a components.json file. Also triggers for "shadcn init", "create an app with --preset", or "switch to --preset".
user-invocable: false
allowed-tools: Bash(npx shadcn@latest *), Bash(pnpm dlx shadcn@latest *), Bash(bunx --bun shadcn@latest *)
---
# shadcn/ui
@@ -13,7 +14,7 @@ A framework for building ui, components and design systems. Components are added
## Current Project Context
```json
!`npx shadcn@latest info --json 2>/dev/null || echo '{"error": "No shadcn project found. Run shadcn init first."}'`
!`npx shadcn@latest info --json`
```
The JSON above contains the project config and installed components. Use `npx shadcn@latest docs <component>` to get documentation and example URLs for any component.

View File

@@ -14,24 +14,24 @@
},
"dependencies": {
"@astrojs/react": "^4.4.2",
"@tailwindcss/vite": "^4.1.18",
"@tailwindcss/vite": "^4.2.1",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"astro": "^5.17.1",
"astro": "^5.18.1",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"tailwindcss": "^4.1.18"
"tailwindcss": "^4.2.1"
},
"devDependencies": {
"@eslint/js": "^9.39.1",
"eslint": "^9.39.1",
"@eslint/js": "^9.39.4",
"eslint": "^9.39.4",
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-refresh": "^0.4.24",
"eslint-plugin-react-refresh": "^0.5.2",
"globals": "^16.5.0",
"prettier": "^3.8.1",
"prettier-plugin-astro": "^0.14.1",
"prettier-plugin-tailwindcss": "^0.7.2",
"typescript": "~5.9.3",
"typescript-eslint": "^8.46.4"
"typescript-eslint": "^8.57.1"
}
}

View File

@@ -13,10 +13,10 @@
"prettier": "^3.8.1",
"prettier-plugin-astro": "^0.14.1",
"prettier-plugin-tailwindcss": "^0.7.2",
"turbo": "^2.8.8",
"turbo": "^2.8.17",
"typescript": "5.9.3"
},
"packageManager": "pnpm@9.0.6",
"packageManager": "pnpm@9.15.9",
"engines": {
"node": ">=20"
}

View File

@@ -12,23 +12,23 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"next": "16.1.6",
"next": "16.1.7",
"next-themes": "^0.4.6",
"react": "^19.2.4",
"react-dom": "^19.2.4"
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@tailwindcss/postcss": "^4.1.18",
"@types/node": "^25.1.0",
"@types/react": "^19.2.10",
"@tailwindcss/postcss": "^4.2.1",
"@types/node": "^25.5.0",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"eslint": "^9.39.2",
"eslint-config-next": "16.1.6",
"eslint": "^9.39.4",
"eslint-config-next": "16.1.7",
"prettier": "^3.8.1",
"prettier-plugin-tailwindcss": "^0.7.2",
"postcss": "^8",
"tailwindcss": "^4.1.18",
"tailwindcss": "^4.2.1",
"typescript": "^5.9.3"
}
}

View File

@@ -14,10 +14,10 @@
"@workspace/typescript-config": "workspace:*",
"prettier": "^3.8.1",
"prettier-plugin-tailwindcss": "^0.7.2",
"turbo": "^2.8.8",
"turbo": "^2.8.17",
"typescript": "5.9.3"
},
"packageManager": "pnpm@9.0.6",
"packageManager": "pnpm@9.15.9",
"engines": {
"node": ">=20"
}

View File

@@ -1,4 +1,4 @@
import { Button } from "@/components/ui/button"
import { Button } from "~/components/ui/button"
export default function Home() {
return (

View File

@@ -10,24 +10,24 @@
"format": "prettier --write \"**/*.{ts,tsx}\""
},
"dependencies": {
"@react-router/node": "7.12.0",
"@react-router/serve": "7.12.0",
"isbot": "^5.1.31",
"@react-router/node": "7.13.1",
"@react-router/serve": "7.13.1",
"isbot": "^5.1.36",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"react-router": "7.12.0"
"react-router": "7.13.1"
},
"devDependencies": {
"@react-router/dev": "7.12.0",
"@tailwindcss/vite": "^4.1.13",
"@react-router/dev": "7.13.1",
"@tailwindcss/vite": "^4.2.1",
"@types/node": "^22",
"@types/react": "^19.2.7",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"prettier": "^3.8.1",
"prettier-plugin-tailwindcss": "^0.7.2",
"tailwindcss": "^4.1.13",
"typescript": "^5.9.2",
"vite": "^7.1.7",
"tailwindcss": "^4.2.1",
"typescript": "^5.9.3",
"vite": "^7.3.1",
"vite-tsconfig-paths": "^5.1.4"
}
}

View File

@@ -11,10 +11,10 @@
"devDependencies": {
"prettier": "^3.8.1",
"prettier-plugin-tailwindcss": "^0.7.2",
"turbo": "^2.8.8",
"turbo": "^2.8.17",
"typescript": "5.9.3"
},
"packageManager": "pnpm@9.0.6",
"packageManager": "pnpm@9.15.9",
"engines": {
"node": ">=20"
}

View File

@@ -12,34 +12,34 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@tailwindcss/vite": "^4.1.18",
"@tanstack/react-devtools": "^0.7.0",
"@tanstack/react-router": "^1.132.0",
"@tanstack/react-router-devtools": "^1.132.0",
"@tanstack/react-router-ssr-query": "^1.131.7",
"@tanstack/react-start": "^1.132.0",
"@tanstack/router-plugin": "^1.132.0",
"@tailwindcss/vite": "^4.2.1",
"@tanstack/react-devtools": "^0.10.0",
"@tanstack/react-router": "^1.167.4",
"@tanstack/react-router-devtools": "^1.166.9",
"@tanstack/react-router-ssr-query": "^1.166.9",
"@tanstack/react-start": "^1.166.15",
"@tanstack/router-plugin": "^1.166.13",
"nitro": "latest",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"tailwindcss": "^4.0.6",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"tailwindcss": "^4.2.1",
"vite-tsconfig-paths": "^5.1.4"
},
"devDependencies": {
"@tanstack/devtools-vite": "^0.3.11",
"@tanstack/eslint-config": "^0.3.0",
"@testing-library/dom": "^10.4.0",
"@testing-library/react": "^16.2.0",
"@types/node": "^22.10.2",
"@types/react": "^19.2.0",
"@types/react-dom": "^19.2.0",
"@vitejs/plugin-react": "^5.0.4",
"jsdom": "^27.0.0",
"prettier": "^3.5.3",
"@tanstack/devtools-vite": "^0.6.0",
"@tanstack/eslint-config": "^0.4.0",
"@testing-library/dom": "^10.4.1",
"@testing-library/react": "^16.3.2",
"@types/node": "^22.19.15",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.2.0",
"jsdom": "^27.4.0",
"prettier": "^3.8.1",
"prettier-plugin-tailwindcss": "^0.7.2",
"typescript": "^5.7.2",
"vite": "^7.1.7",
"vitest": "^3.0.5",
"typescript": "^5.9.3",
"vite": "^7.3.1",
"vitest": "^3.2.4",
"web-vitals": "^5.1.0"
}
}

View File

@@ -12,10 +12,10 @@
"devDependencies": {
"prettier": "^3.8.1",
"prettier-plugin-tailwindcss": "^0.7.2",
"turbo": "^2.8.8",
"turbo": "^2.8.17",
"typescript": "5.9.3"
},
"packageManager": "pnpm@9.0.6",
"packageManager": "pnpm@9.15.9",
"engines": {
"node": ">=20"
}

View File

@@ -12,25 +12,25 @@
"preview": "vite preview"
},
"dependencies": {
"@tailwindcss/vite": "^4.1.17",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"tailwindcss": "^4.1.17"
"@tailwindcss/vite": "^4.2.1",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"tailwindcss": "^4.2.1"
},
"devDependencies": {
"@eslint/js": "^9.39.1",
"@types/node": "^24.10.1",
"@types/react": "^19.2.5",
"@eslint/js": "^9.39.4",
"@types/node": "^24.12.0",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.1",
"eslint": "^9.39.1",
"@vitejs/plugin-react": "^5.2.0",
"eslint": "^9.39.4",
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-refresh": "^0.4.24",
"eslint-plugin-react-refresh": "^0.5.2",
"globals": "^16.5.0",
"prettier": "^3.8.1",
"prettier-plugin-tailwindcss": "^0.7.2",
"typescript": "~5.9.3",
"typescript-eslint": "^8.46.4",
"vite": "^7.2.4"
"typescript-eslint": "^8.57.1",
"vite": "^7.3.1"
}
}

View File

@@ -12,10 +12,10 @@
"devDependencies": {
"prettier": "^3.8.1",
"prettier-plugin-tailwindcss": "^0.7.2",
"turbo": "^2.8.8",
"turbo": "^2.8.17",
"typescript": "5.9.3"
},
"packageManager": "pnpm@9.0.6",
"packageManager": "pnpm@9.15.9",
"engines": {
"node": ">=20"
}