mirror of
https://github.com/shadcn-ui/ui.git
synced 2026-06-16 04:11:34 +00:00
Compare commits
16 Commits
shadcn/cod
...
claude/fix
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2139f1ac6c | ||
|
|
85cceaa7a9 | ||
|
|
31dbc6fc91 | ||
|
|
8db2be8b09 | ||
|
|
a8bd00466a | ||
|
|
e78bb7b4f3 | ||
|
|
acaa0953df | ||
|
|
632e2c012e | ||
|
|
78f6a8b0f0 | ||
|
|
a9f997d00a | ||
|
|
dbe1fa76b3 | ||
|
|
74c4c7508b | ||
|
|
4809da6f9c | ||
|
|
7ffefce9e0 | ||
|
|
6cad522930 | ||
|
|
d683b05d7f |
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
})
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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._
|
||||
|
||||
<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?
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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"
|
||||
/>
|
||||
|
||||
|
||||
@@ -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
|
||||
---
|
||||
|
||||
@@ -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"
|
||||
```
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 |
|
||||
| ------ | ------------------- | ----------- |
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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" />
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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" />
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Typography
|
||||
description: Styles for headings, paragraphs, lists...etc
|
||||
description: Styles for headings, paragraphs, lists, etc.
|
||||
base: base
|
||||
component: true
|
||||
---
|
||||
|
||||
@@ -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 |
|
||||
| ------ | ------------------- | ----------- |
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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" />
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -83,8 +83,8 @@ import {
|
||||
<DropdownMenuItem>Profile</DropdownMenuItem>
|
||||
<DropdownMenuItem>Billing</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>Team</DropdownMenuItem>
|
||||
<DropdownMenuItem>Subscription</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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" />
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Typography
|
||||
description: Styles for headings, paragraphs, lists...etc
|
||||
description: Styles for headings, paragraphs, lists, etc.
|
||||
base: radix
|
||||
component: true
|
||||
---
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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": [
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 }) {
|
||||
|
||||
@@ -56,7 +56,6 @@ Here's an example of a valid registry:
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -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
@@ -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"
|
||||
}
|
||||
@@ -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"],
|
||||
|
||||
@@ -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
@@ -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",
|
||||
|
||||
@@ -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"])
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Button } from "~/components/ui/button"
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user