diff --git a/.changeset/curvy-taxis-help.md b/.changeset/curvy-taxis-help.md new file mode 100644 index 0000000000..c17b6d1b5a --- /dev/null +++ b/.changeset/curvy-taxis-help.md @@ -0,0 +1,5 @@ +--- +"shadcn": patch +--- + +do not add ring for v3 diff --git a/.changeset/green-eels-shout.md b/.changeset/green-eels-shout.md new file mode 100644 index 0000000000..a7013814ca --- /dev/null +++ b/.changeset/green-eels-shout.md @@ -0,0 +1,5 @@ +--- +"shadcn": patch +--- + +cache registry calls diff --git a/.changeset/shaggy-months-tease.md b/.changeset/shaggy-months-tease.md new file mode 100644 index 0000000000..eb292424f7 --- /dev/null +++ b/.changeset/shaggy-months-tease.md @@ -0,0 +1,5 @@ +--- +"shadcn": patch +--- + +check for empty css vars diff --git a/.changeset/tasty-walls-drum.md b/.changeset/tasty-walls-drum.md new file mode 100644 index 0000000000..ea8d908288 --- /dev/null +++ b/.changeset/tasty-walls-drum.md @@ -0,0 +1,5 @@ +--- +"shadcn": minor +--- + +add support for route install for react-router and laravel diff --git a/.github/workflows/issue-stale.yml b/.github/workflows/issue-stale.yml index 500d781b08..c86d3eef2f 100644 --- a/.github/workflows/issue-stale.yml +++ b/.github/workflows/issue-stale.yml @@ -1,5 +1,5 @@ # Adapted from vercel/next.js -name: Issue Stale +name: "Stale issue handler" on: workflow_dispatch: schedule: @@ -11,17 +11,35 @@ jobs: runs-on: ubuntu-latest if: github.repository_owner == 'shadcn-ui' steps: - - uses: actions/stale@v4 - id: stale-no-repro - name: "Close stale issues with no reproduction" + - uses: actions/stale@v9 + id: issue-stale + name: "Mark stale issues, close stale issues" with: repo-token: ${{ secrets.STALE_TOKEN }} - close-issue-message: "This issue has been automatically closed because it received no activity for a while. If you think it was closed by accident, please reopen or leave a comment. Thank you.\n(This is an automated message.)" + ascending: true days-before-issue-close: 7 - days-before-issue-stale: 30 - stale-pr-label: "stale?" - days-before-pr-close: 7 - days-before-pr-stale: 15 - only-pr-labels: "postpone: more info or changes requested,please add a reproduction" + days-before-issue-stale: 365 # ~2 years + days-before-pr-stale: -1 + days-before-pr-close: -1 + remove-issue-stale-when-updated: true + stale-issue-label: "stale?" exempt-issue-labels: "roadmap,next,bug" + stale-issue-message: "This issue has been automatically marked as stale due to one year of inactivity. It will be closed in 7 days unless there’s further input. If you believe this issue is still relevant, please leave a comment or provide updated details. Thank you." + close-issue-message: "This issue has been automatically closed due to one year of inactivity. If you’re still experiencing a similar problem or have additional details to share, please open a new issue following our current issue template. Your updated report helps us investigate and address concerns more efficiently. Thank you for your understanding!" + operations-per-run: 300 # 1 operation per 100 issues, the rest is to label/comment/close + - uses: actions/stale@v9 + id: pr-state + name: "Mark stale PRs, close stale PRs" + with: + repo-token: ${{ secrets.STALE_TOKEN }} + ascending: true + days-before-issue-close: -1 + days-before-issue-stale: -1 + days-before-pr-close: 7 + days-before-pr-stale: 365 # PRs with no activity in over 90 days will be marked as stale + remove-pr-stale-when-updated: true + exempt-pr-labels: "roadmap,nex,awaiting-approval,work-in-progress" + stale-pr-label: "stale?" + stale-pr-message: "This PR has been automatically marked as stale due to one year of inactivity. It will be closed in 7 days unless there’s further input. If you believe this PR is still relevant, please leave a comment or provide updated details. Thank you." + close-pr-message: "This PR has been automatically closed due to one year of inactivity. Thank you for your understanding!" operations-per-run: 300 # 1 operation per 100 issues, the rest is to label/comment/close diff --git a/apps/v4/__registry__/index.tsx b/apps/v4/__registry__/index.tsx index 7feee16455..624cf5bfc8 100644 --- a/apps/v4/__registry__/index.tsx +++ b/apps/v4/__registry__/index.tsx @@ -1446,6 +1446,7 @@ export const Index: Record = { "dropdown-menu", "avatar", "switch", + "label", ], files: [ { @@ -1783,6 +1784,7 @@ export const Index: Record = { "dropdown-menu", "avatar", "button", + "label", ], files: [ { @@ -3785,4 +3787,43 @@ export const Index: Record = { }), meta: undefined, }, + "products-01": { + name: "products-01", + description: "A table of products", + type: "registry:block", + registryDependencies: [ + "checkbox", + "badge", + "button", + "dropdown-menu", + "pagination", + "table", + "tabs", + "select", + ], + files: [ + { + path: "registry/blocks/products-01/page.tsx", + type: "registry:page", + target: "app/products/page.tsx", + }, + { + path: "registry/blocks/products-01/components/products-table.tsx", + type: "registry:component", + target: "", + }, + ], + component: React.lazy(async () => { + const mod = await import( + "@/registry/new-york-v4/blocks/products-01/page.tsx" + ) + const exportName = + Object.keys(mod).find( + (key) => + typeof mod[key] === "function" || typeof mod[key] === "object" + ) || item.name + return { default: mod.default || mod[exportName] } + }), + meta: undefined, + }, } diff --git a/apps/v4/app/(app)/page.tsx b/apps/v4/app/(app)/page.tsx index 6901f9bd85..20cbcaec68 100644 --- a/apps/v4/app/(app)/page.tsx +++ b/apps/v4/app/(app)/page.tsx @@ -49,7 +49,7 @@ import { TooltipDemo } from "@/components/tooltip-demo" export default function SinkPage() { return ( -
+
@@ -83,7 +83,7 @@ export default function SinkPage() { - + diff --git a/apps/v4/app/globals.css b/apps/v4/app/globals.css index d15228cdca..238c4b6ae4 100644 --- a/apps/v4/app/globals.css +++ b/apps/v4/app/globals.css @@ -5,6 +5,8 @@ @custom-variant dark (&:is(.dark *)); :root { + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); --card: oklch(1 0 0); --card-foreground: oklch(0.145 0 0); --popover: oklch(1 0 0); @@ -21,7 +23,7 @@ --destructive-foreground: oklch(0.577 0.245 27.325); --border: oklch(0.922 0 0); --input: oklch(0.922 0 0); - --ring: oklch(0.87 0 0); + --ring: oklch(0.708 0 0); --chart-1: oklch(0.646 0.222 41.116); --chart-2: oklch(0.6 0.118 184.704); --chart-3: oklch(0.398 0.07 227.392); @@ -35,9 +37,7 @@ --sidebar-accent: oklch(0.97 0 0); --sidebar-accent-foreground: oklch(0.205 0 0); --sidebar-border: oklch(0.922 0 0); - --sidebar-ring: oklch(0.87 0 0); - --background: oklch(1 0 0); - --foreground: oklch(0.145 0 0); + --sidebar-ring: oklch(0.708 0 0); } .dark { @@ -59,7 +59,7 @@ --destructive-foreground: oklch(0.637 0.237 25.331); --border: oklch(0.269 0 0); --input: oklch(0.269 0 0); - --ring: oklch(0.439 0 0); + --ring: oklch(0.556 0 0); --chart-1: oklch(0.488 0.243 264.376); --chart-2: oklch(0.696 0.17 162.48); --chart-3: oklch(0.769 0.188 70.08); @@ -129,8 +129,8 @@ } @theme inline { - --font-sans: var(--font-geist-sans); - --font-mono: var(--font-geist-mono); + --font-sans: var(--font-sans); + --font-mono: var(--font-mono); --color-background: var(--background); --color-foreground: var(--foreground); --color-card: var(--card); diff --git a/apps/v4/app/layout.tsx b/apps/v4/app/layout.tsx index 70f708eac4..930c72e6e8 100644 --- a/apps/v4/app/layout.tsx +++ b/apps/v4/app/layout.tsx @@ -1,6 +1,5 @@ import type { Metadata, Viewport } from "next" -import { GeistMono } from "geist/font/mono" -import { GeistSans } from "geist/font/sans" +import { Geist_Mono as FontMono, Inter as FontSans } from "next/font/google" import { cn } from "@/lib/utils" import { Analytics } from "@/components/analytics" @@ -10,9 +9,15 @@ import { siteConfig } from "@/www/config/site" import "./globals.css" -const fontSans = GeistSans +const fontSans = FontSans({ + subsets: ["latin"], + variable: "--font-sans", +}) -const fontMono = GeistMono +const fontMono = FontMono({ + subsets: ["latin"], + variable: "--font-mono", +}) const META_THEME_COLORS = { light: "#ffffff", diff --git a/apps/v4/components/avatar-demo.tsx b/apps/v4/components/avatar-demo.tsx index 8766ff251d..d183633aa5 100644 --- a/apps/v4/components/avatar-demo.tsx +++ b/apps/v4/components/avatar-demo.tsx @@ -6,7 +6,7 @@ import { export function AvatarDemo() { return ( -
+
CN diff --git a/apps/v4/components/badge-demo.tsx b/apps/v4/components/badge-demo.tsx index 85768b0f87..73acd07a3a 100644 --- a/apps/v4/components/badge-demo.tsx +++ b/apps/v4/components/badge-demo.tsx @@ -5,7 +5,7 @@ import { Badge } from "@/registry/new-york-v4/ui/badge" export function BadgeDemo() { return (
-
+
Badge Secondary Destructive @@ -34,7 +34,7 @@ export function BadgeDemo() { 20+
-
+
Link diff --git a/apps/v4/components/button-demo.tsx b/apps/v4/components/button-demo.tsx index 28120886cd..78cb85a888 100644 --- a/apps/v4/components/button-demo.tsx +++ b/apps/v4/components/button-demo.tsx @@ -5,7 +5,7 @@ import { Button } from "@/registry/new-york-v4/ui/button" export function ButtonDemo() { return (
-
+
@@ -23,7 +23,7 @@ export function ButtonDemo() { Please wait
-
+
-
+
+ +
+
+
+ + + + + + + Product + Price + Stock + Status + Date Added + + + + + {products.map((product) => ( + + + + + {product.name} + + ${product.price.toFixed(2)} + + {product.stock} + + + {product.status} + + + + {new Date(product.dateAdded).toLocaleDateString("en-US", { + month: "long", + day: "numeric", + year: "numeric", + })} + + + + + + + + Edit + + Delete + + + + + + ))} + +
+
+
+ + + + + + + 1 + + + + 2 + + + + 3 + + + + + + + + + +
+
+ ) +} diff --git a/apps/v4/registry/new-york-v4/blocks/products-01/page.tsx b/apps/v4/registry/new-york-v4/blocks/products-01/page.tsx new file mode 100644 index 0000000000..bd780f0bb8 --- /dev/null +++ b/apps/v4/registry/new-york-v4/blocks/products-01/page.tsx @@ -0,0 +1,173 @@ +import { ProductsTable } from "@/registry/new-york-v4/blocks/products-01/components/products-table" + +// Load from database. +const products = [ + { + id: "1", + name: "BJÖRKSNÄS Dining Table", + price: 599.99, + stock: 12, + dateAdded: "2023-06-15", + status: "In Stock", + }, + { + id: "2", + name: "POÄNG Armchair", + price: 249.99, + stock: 28, + dateAdded: "2023-07-22", + status: "In Stock", + }, + { + id: "3", + name: "MALM Bed Frame", + price: 399.99, + stock: 15, + dateAdded: "2023-08-05", + status: "In Stock", + }, + { + id: "4", + name: "KALLAX Shelf Unit", + price: 179.99, + stock: 32, + dateAdded: "2023-09-12", + status: "In Stock", + }, + { + id: "5", + name: "STOCKHOLM Rug", + price: 299.99, + stock: 8, + dateAdded: "2023-10-18", + status: "Low Stock", + }, + { + id: "6", + name: "KIVIK Sofa", + price: 899.99, + stock: 6, + dateAdded: "2023-11-02", + status: "Low Stock", + }, + { + id: "7", + name: "LISABO Coffee Table", + price: 149.99, + stock: 22, + dateAdded: "2023-11-29", + status: "In Stock", + }, + { + id: "8", + name: "HEMNES Bookcase", + price: 249.99, + stock: 17, + dateAdded: "2023-12-10", + status: "In Stock", + }, + { + id: "9", + name: "EKEDALEN Dining Chairs (Set of 2)", + price: 199.99, + stock: 14, + dateAdded: "2024-01-05", + status: "In Stock", + }, + { + id: "10", + name: "FRIHETEN Sleeper Sofa", + price: 799.99, + stock: 9, + dateAdded: "2024-01-18", + status: "Low Stock", + }, + { + id: "11", + name: "NORDEN Extendable Table", + price: 499.99, + stock: 11, + dateAdded: "2024-01-25", + status: "In Stock", + }, + { + id: "12", + name: "BILLY Bookcase", + price: 129.99, + stock: 42, + dateAdded: "2024-02-03", + status: "In Stock", + }, + { + id: "13", + name: "STRANDMON Wing Chair", + price: 349.99, + stock: 16, + dateAdded: "2024-02-12", + status: "In Stock", + }, + { + id: "14", + name: "MALM Dresser", + price: 279.99, + stock: 19, + dateAdded: "2024-02-27", + status: "In Stock", + }, + { + id: "15", + name: "BRIMNES TV Unit", + price: 149.99, + stock: 23, + dateAdded: "2024-03-08", + status: "In Stock", + }, + { + id: "16", + name: "SÖDERHAMN Sectional Sofa", + price: 1299.99, + stock: 5, + dateAdded: "2024-03-15", + status: "Low Stock", + }, + { + id: "17", + name: "BEKANT Desk", + price: 249.99, + stock: 18, + dateAdded: "2024-03-22", + status: "In Stock", + }, + { + id: "18", + name: "IVAR Storage System", + price: 199.99, + stock: 14, + dateAdded: "2024-04-01", + status: "In Stock", + }, + { + id: "19", + name: "RIBBA Picture Frame Set", + price: 49.99, + stock: 36, + dateAdded: "2024-04-09", + status: "In Stock", + }, + { + id: "20", + name: "EKTORP Loveseat", + price: 499.99, + stock: 12, + dateAdded: "2024-04-15", + status: "In Stock", + }, +] + +export default function ProductsPage() { + return ( +
+ +
+ ) +} diff --git a/apps/v4/registry/new-york-v4/ui/badge.tsx b/apps/v4/registry/new-york-v4/ui/badge.tsx index 268ea771c2..37e088abbf 100644 --- a/apps/v4/registry/new-york-v4/ui/badge.tsx +++ b/apps/v4/registry/new-york-v4/ui/badge.tsx @@ -5,7 +5,7 @@ import { cva, type VariantProps } from "class-variance-authority" import { cn } from "@/lib/utils" const badgeVariants = cva( - "inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-auto", + "inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden", { variants: { variant: { diff --git a/apps/v4/registry/new-york-v4/ui/button.tsx b/apps/v4/registry/new-york-v4/ui/button.tsx index 761d2fe9fa..cd0857a005 100644 --- a/apps/v4/registry/new-york-v4/ui/button.tsx +++ b/apps/v4/registry/new-york-v4/ui/button.tsx @@ -5,7 +5,7 @@ import { cva, type VariantProps } from "class-variance-authority" import { cn } from "@/lib/utils" const buttonVariants = cva( - "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-[color,box-shadow] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-[color,box-shadow] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", { variants: { variant: { @@ -22,7 +22,7 @@ const buttonVariants = cva( }, size: { default: "h-9 px-4 py-2 has-[>svg]:px-3", - sm: "h-8 rounded-md px-3 has-[>svg]:px-2.5", + sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5", lg: "h-10 rounded-md px-6 has-[>svg]:px-4", icon: "size-9", }, diff --git a/apps/v4/registry/new-york-v4/ui/form.tsx b/apps/v4/registry/new-york-v4/ui/form.tsx index 077f7f4de7..fc7dd133d0 100644 --- a/apps/v4/registry/new-york-v4/ui/form.tsx +++ b/apps/v4/registry/new-york-v4/ui/form.tsx @@ -137,7 +137,7 @@ function FormDescription({ className, ...props }: React.ComponentProps<"p">) { function FormMessage({ className, ...props }: React.ComponentProps<"p">) { const { error, formMessageId } = useFormField() - const body = error ? String(error?.message) : props.children + const body = error ? String(error?.message ?? "") : props.children if (!body) { return null diff --git a/apps/v4/registry/new-york-v4/ui/label.tsx b/apps/v4/registry/new-york-v4/ui/label.tsx index f948bc3674..fb5fbc3eee 100644 --- a/apps/v4/registry/new-york-v4/ui/label.tsx +++ b/apps/v4/registry/new-york-v4/ui/label.tsx @@ -13,7 +13,7 @@ function Label({ span]:line-clamp-1", + "border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive flex h-9 w-full items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className )} {...props} diff --git a/apps/v4/registry/new-york-v4/ui/sidebar.tsx b/apps/v4/registry/new-york-v4/ui/sidebar.tsx index 9e4ad53b26..6417f43ccf 100644 --- a/apps/v4/registry/new-york-v4/ui/sidebar.tsx +++ b/apps/v4/registry/new-york-v4/ui/sidebar.tsx @@ -183,10 +183,6 @@ function Sidebar({ if (isMobile) { return ( - - Sidebar - Displays the mobile sidebar. - + + Sidebar + Displays the mobile sidebar. +
{children}
@@ -217,7 +217,7 @@ function Sidebar({ {/* This is what handles the sidebar gap on desktop */}
) {
svg]:size-4 [&>svg]:shrink-0", + "text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0", "group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0", className )} diff --git a/apps/v4/registry/new-york-v4/ui/table.tsx b/apps/v4/registry/new-york-v4/ui/table.tsx index fed5e35def..f1ecaaaffa 100644 --- a/apps/v4/registry/new-york-v4/ui/table.tsx +++ b/apps/v4/registry/new-york-v4/ui/table.tsx @@ -6,7 +6,10 @@ import { cn } from "@/lib/utils" function Table({ className, ...props }: React.ComponentProps<"table">) { return ( -
+
) {
[role=checkbox]]:translate-y-[2px]", + "text-muted-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]", className )} {...props} @@ -80,7 +83,7 @@ function TableCell({ className, ...props }: React.ComponentProps<"td">) { [role=checkbox]]:translate-y-[2px]", + "p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]", className )} {...props} diff --git a/apps/v4/registry/new-york-v4/ui/tabs.tsx b/apps/v4/registry/new-york-v4/ui/tabs.tsx index ed9babdb58..03f538b299 100644 --- a/apps/v4/registry/new-york-v4/ui/tabs.tsx +++ b/apps/v4/registry/new-york-v4/ui/tabs.tsx @@ -42,7 +42,7 @@ function TabsTrigger({ ) { @@ -46,7 +46,7 @@ function TooltipContent({ data-slot="tooltip-content" sideOffset={sideOffset} className={cn( - "bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-w-sm rounded-md px-3 py-1.5 text-xs", + "bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit rounded-md px-3 py-1.5 text-xs text-balance", className )} {...props} diff --git a/apps/v4/scripts/build-registry.mts b/apps/v4/scripts/build-registry.mts index 24cbd2ad09..4af9071c0c 100644 --- a/apps/v4/scripts/build-registry.mts +++ b/apps/v4/scripts/build-registry.mts @@ -48,6 +48,32 @@ const registry = { }, ], }, + { + name: "products-01", + description: "A table of products", + type: "registry:block", + registryDependencies: [ + "checkbox", + "badge", + "button", + "dropdown-menu", + "pagination", + "table", + "tabs", + "select", + ], + files: [ + { + path: "blocks/products-01/page.tsx", + type: "registry:page", + target: "app/products/page.tsx", + }, + { + path: "blocks/products-01/components/products-table.tsx", + type: "registry:component", + }, + ], + }, ].filter((item) => { return !DEPRECATED_ITEMS.includes(item.name) }) diff --git a/apps/www/__registry__/index.tsx b/apps/www/__registry__/index.tsx index 52cdfa5559..5f33147abd 100644 --- a/apps/www/__registry__/index.tsx +++ b/apps/www/__registry__/index.tsx @@ -934,7 +934,7 @@ export const Index: Record = { name: "sidebar-09", description: "Collapsible nested sidebars.", type: "registry:block", - registryDependencies: ["sidebar","breadcrumb","separator","collapsible","dropdown-menu","avatar","switch"], + registryDependencies: ["sidebar","breadcrumb","separator","collapsible","dropdown-menu","avatar","switch","label"], files: [{ path: "registry/new-york/blocks/sidebar-09/page.tsx", type: "registry:page", @@ -1143,7 +1143,7 @@ export const Index: Record = { name: "sidebar-16", description: "A sidebar with a sticky site header.", type: "registry:block", - registryDependencies: ["sidebar","breadcrumb","separator","collapsible","dropdown-menu","avatar","button"], + registryDependencies: ["sidebar","breadcrumb","separator","collapsible","dropdown-menu","avatar","button","label"], files: [{ path: "registry/new-york/blocks/sidebar-16/page.tsx", type: "registry:page", @@ -6232,7 +6232,7 @@ export const Index: Record = { name: "sidebar-09", description: "Collapsible nested sidebars.", type: "registry:block", - registryDependencies: ["sidebar","breadcrumb","separator","collapsible","dropdown-menu","avatar","switch"], + registryDependencies: ["sidebar","breadcrumb","separator","collapsible","dropdown-menu","avatar","switch","label"], files: [{ path: "registry/default/blocks/sidebar-09/page.tsx", type: "registry:page", @@ -6441,7 +6441,7 @@ export const Index: Record = { name: "sidebar-16", description: "A sidebar with a sticky site header.", type: "registry:block", - registryDependencies: ["sidebar","breadcrumb","separator","collapsible","dropdown-menu","avatar","button"], + registryDependencies: ["sidebar","breadcrumb","separator","collapsible","dropdown-menu","avatar","button","label"], files: [{ path: "registry/default/blocks/sidebar-16/page.tsx", type: "registry:page", diff --git a/apps/www/app/(app)/examples/mail/data.tsx b/apps/www/app/(app)/examples/mail/data.tsx index 2807a4a24e..1c9699f252 100644 --- a/apps/www/app/(app)/examples/mail/data.tsx +++ b/apps/www/app/(app)/examples/mail/data.tsx @@ -186,7 +186,7 @@ export const accounts = [ }, { label: "Alicia Koch", - email: "alicia@gmail.com", + email: "alicia@example.com", icon: ( Gmail @@ -199,7 +199,7 @@ export const accounts = [ }, { label: "Alicia Koch", - email: "alicia@me.com", + email: "alicia@example.com", icon: ( iCloud diff --git a/apps/www/app/(app)/page.tsx b/apps/www/app/(app)/page.tsx index f59b1fde83..d26f82c532 100644 --- a/apps/www/app/(app)/page.tsx +++ b/apps/www/app/(app)/page.tsx @@ -50,7 +50,7 @@ export default function IndexPage() { {description} - Astro + + + + + Astro + TailwindCSS + - +
+ +
``` diff --git a/apps/www/content/docs/installation/index.mdx b/apps/www/content/docs/installation/index.mdx index 202dd41754..414f1a995c 100644 --- a/apps/www/content/docs/installation/index.mdx +++ b/apps/www/content/docs/installation/index.mdx @@ -32,18 +32,28 @@ description: How to install dependencies and structure your app.

Vite

- + + + +

Laravel

+
+ + - Remix - + -

Remix

+

React Router

Astro

- - - - -

Laravel

-
- **Update:** We have added full support for React 19 and Tailwind v4 in the - `canary` release. See the docs for [Tailwind v4](/docs/tailwind-v4) for more - information. - - ### Create project @@ -16,47 +10,31 @@ description: Install and configure Laravel with Inertia Start by creating a new Laravel project with Inertia and React using the laravel installer `laravel new my-app`: ```bash -laravel new my-app --typescript --breeze --stack=react --git --no-interaction +laravel new my-app --react ``` -### Run the CLI - -Run the `shadcn` init command to setup your project: - -```bash -npx shadcn@latest init -``` - -### Configure components.json - -You will be asked a few questions to configure `components.json`: - -```txt showLineNumbers -Which style would you like to use? -Which color would you like to use as base color? -Do you want to use CSS variables for colors? › yes -``` - -### That's it +### Add Components You can now start adding components to your project. ```bash -npx shadcn@latest add button +npx shadcn@latest add switch ``` -The command above will add the `Button` component to your project. You can then import it like this: +The command above will add the `Switch` component to `resources/js/components/ui/switch.tsx`. You can then import it like this: ```tsx {1,6} showLineNumbers -import { Button } from "@/Components/ui/button" +import { Switch } from "@/components/ui/switch" -export default function Home() { +const MyPage = () => { return (
- +
) } + +export default MyPage ``` diff --git a/apps/www/content/docs/installation/manual.mdx b/apps/www/content/docs/installation/manual.mdx index 058fa03f80..255ee9c363 100644 --- a/apps/www/content/docs/installation/manual.mdx +++ b/apps/www/content/docs/installation/manual.mdx @@ -36,132 +36,140 @@ Configure the path aliases in your `tsconfig.json` file. The `@` alias is a preference. You can use other aliases if you want. -### Configure tailwind.config.js - -Here's what my `tailwind.config.js` file looks like: - -```js title="tailwind.config.js" -/** @type {import('tailwindcss').Config} */ -module.exports = { - darkMode: ["class"], - content: ["app/**/*.{ts,tsx}", "components/**/*.{ts,tsx}"], - theme: { - extend: { - colors: { - border: "hsl(var(--border))", - input: "hsl(var(--input))", - ring: "hsl(var(--ring))", - background: "hsl(var(--background))", - foreground: "hsl(var(--foreground))", - primary: { - DEFAULT: "hsl(var(--primary))", - foreground: "hsl(var(--primary-foreground))", - }, - secondary: { - DEFAULT: "hsl(var(--secondary))", - foreground: "hsl(var(--secondary-foreground))", - }, - destructive: { - DEFAULT: "hsl(var(--destructive))", - foreground: "hsl(var(--destructive-foreground))", - }, - muted: { - DEFAULT: "hsl(var(--muted))", - foreground: "hsl(var(--muted-foreground))", - }, - accent: { - DEFAULT: "hsl(var(--accent))", - foreground: "hsl(var(--accent-foreground))", - }, - popover: { - DEFAULT: "hsl(var(--popover))", - foreground: "hsl(var(--popover-foreground))", - }, - card: { - DEFAULT: "hsl(var(--card))", - foreground: "hsl(var(--card-foreground))", - }, - }, - borderRadius: { - lg: `var(--radius)`, - md: `calc(var(--radius) - 2px)`, - sm: "calc(var(--radius) - 4px)", - }, - }, - }, - plugins: [require("tailwindcss-animate")], -} -``` - ### Configure styles Add the following to your styles/globals.css file. You can learn more about using CSS variables for theming in the [theming section](/docs/theming). -```css title="globals.css" -@tailwind base; -@tailwind components; -@tailwind utilities; +```css showLineNumbers title="src/styles/globals.css" +@import "tailwindcss"; -@layer base { - :root { - --background: 0 0% 100%; - --foreground: 222.2 47.4% 11.2%; - --muted: 210 40% 96.1%; - --muted-foreground: 215.4 16.3% 46.9%; - --popover: 0 0% 100%; - --popover-foreground: 222.2 47.4% 11.2%; - --border: 214.3 31.8% 91.4%; - --input: 214.3 31.8% 91.4%; - --card: 0 0% 100%; - --card-foreground: 222.2 47.4% 11.2%; - --primary: 222.2 47.4% 11.2%; - --primary-foreground: 210 40% 98%; - --secondary: 210 40% 96.1%; - --secondary-foreground: 222.2 47.4% 11.2%; - --accent: 210 40% 96.1%; - --accent-foreground: 222.2 47.4% 11.2%; - --destructive: 0 100% 50%; - --destructive-foreground: 210 40% 98%; - --ring: 215 20.2% 65.1%; - --radius: 0.5rem; - } +@plugin 'tailwindcss-animate'; - .dark { - --background: 224 71% 4%; - --foreground: 213 31% 91%; - --muted: 223 47% 11%; - --muted-foreground: 215.4 16.3% 56.9%; - --accent: 216 34% 17%; - --accent-foreground: 210 40% 98%; - --popover: 224 71% 4%; - --popover-foreground: 215 20.2% 65.1%; - --border: 216 34% 17%; - --input: 216 34% 17%; - --card: 224 71% 4%; - --card-foreground: 213 31% 91%; - --primary: 210 40% 98%; - --primary-foreground: 222.2 47.4% 1.2%; - --secondary: 222.2 47.4% 11.2%; - --secondary-foreground: 210 40% 98%; - --destructive: 0 63% 31%; - --destructive-foreground: 210 40% 98%; - --ring: 216 34% 17%; - } +@custom-variant dark (&:is(.dark *)); + +:root { + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --destructive-foreground: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --radius: 0.625rem; + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); +} + +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.145 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.145 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.985 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.396 0.141 25.723); + --destructive-foreground: oklch(0.637 0.237 25.331); + --border: oklch(0.269 0 0); + --input: oklch(0.269 0 0); + --ring: oklch(0.439 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(0.269 0 0); + --sidebar-ring: oklch(0.439 0 0); +} + +@theme inline { + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-destructive-foreground: var(--destructive-foreground); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); } @layer base { * { - @apply border-border; + @apply border-border outline-ring/50; } body { - @apply font-sans antialiased bg-background text-foreground; + @apply bg-background text-foreground; } } ``` ### Add a cn helper -```ts title="lib/utils.ts" showLineNumbers +```ts showLineNumbers title="lib/utils.ts" import { clsx, type ClassValue } from "clsx" import { twMerge } from "tailwind-merge" @@ -181,9 +189,9 @@ Create a `components.json` file in the root of your project. "rsc": false, "tsx": true, "tailwind": { - "config": "tailwind.config.js", - "css": "src/index.css", - "baseColor": "zinc", + "config": "", + "css": "src/styles/globals.css", + "baseColor": "neutral", "cssVariables": true, "prefix": "" }, diff --git a/apps/www/content/docs/installation/next.mdx b/apps/www/content/docs/installation/next.mdx index 4a253e3b30..a2b8915ba6 100644 --- a/apps/www/content/docs/installation/next.mdx +++ b/apps/www/content/docs/installation/next.mdx @@ -1,14 +1,8 @@ --- title: Next.js -description: Install and configure Next.js. +description: Install and configure shadcn/ui for Next.js. --- - - **Update:** We have added full support for React 19 and Tailwind v4 in the - `canary` release. See the docs for [Tailwind v4](/docs/tailwind-v4) for more - information. - - ### Create project @@ -19,27 +13,9 @@ Run the `init` command to create a new Next.js project or to setup an existing o npx shadcn@latest init ``` - +Choose between a Next.js project or a Monorepo. -You can use the `-d` flag for defaults i.e `new-york`, `zinc` and `yes` for the css variables. - -```bash -npx shadcn@latest init -d -``` - - - -### Configure components.json - -You will be asked a few questions to configure `components.json`: - -```txt showLineNumbers -Which style would you like to use? › New York -Which color would you like to use as base color? › Zinc -Do you want to use CSS variables for colors? › no / yes -``` - -### That's it +### Add Components You can now start adding components to your project. diff --git a/apps/www/content/docs/installation/react-router.mdx b/apps/www/content/docs/installation/react-router.mdx new file mode 100644 index 0000000000..684a88432d --- /dev/null +++ b/apps/www/content/docs/installation/react-router.mdx @@ -0,0 +1,53 @@ +--- +title: React Router +description: Install and configure shadcn/ui for React Router. +--- + + + +### Create project + +```bash +npx create-react-router@latest my-app +``` + +### Run the CLI + +Run the `shadcn-ui` init command to setup your project: + +```bash +npx shadcn@latest init +``` + +### Add Components + +You can now start adding components to your project. + +```bash +npx shadcn@latest add button +``` + +The command above will add the `Button` component to your project. You can then import it like this: + +```tsx showLineNumbers title="app/routes/home.tsx" +import { Button } from "~/components/ui/button" + +import type { Route } from "./+types/home" + +export function meta({}: Route.MetaArgs) { + return [ + { title: "New React Router App" }, + { name: "description", content: "Welcome to React Router!" }, + ] +} + +export default function Home() { + return ( +
+ +
+ ) +} +``` + +
diff --git a/apps/www/content/docs/installation/remix.mdx b/apps/www/content/docs/installation/remix.mdx index a579e8213c..e319cba2d8 100644 --- a/apps/www/content/docs/installation/remix.mdx +++ b/apps/www/content/docs/installation/remix.mdx @@ -1,8 +1,14 @@ --- title: Remix -description: Install and configure Remix. +description: Install and configure shadcn/ui for Remix. --- + + +**Note:** This guide is for Remix. For React Router, see the [React Router](/docs/installation/react-router) guide. + + + ### Create project diff --git a/apps/www/content/docs/installation/tanstack.mdx b/apps/www/content/docs/installation/tanstack.mdx index 82145e8ee9..0b1d652b01 100644 --- a/apps/www/content/docs/installation/tanstack.mdx +++ b/apps/www/content/docs/installation/tanstack.mdx @@ -1,175 +1,38 @@ --- title: TanStack Start -description: Install and configure TanStack Start. +description: Install and configure shadcn/ui for TanStack Start. --- - - **Note:** This guide is for TanStack Start and Tailwind v4. If you are using - Tailwind v3, consider the [Basic Starter](#basic-starter) template. **TanStack - Start** works with the **canary** version of `shadcn`. - - -## TanStack Start + Tailwind v4 - ### Create project -Start by creating a new TanStack Start project by following the [Build a Project from Scratch](https://tanstack.com/start/latest/docs/framework/react/build-from-scratch) guide on the TanStack Start website. - -### Add Tailwind - -Install `tailwindcss` and its dependencies. +Start by creating a new TanStack Start project: ```bash -npm install tailwindcss @tailwindcss/postcss postcss +npx create-tsrouter-app@latest my-app --template file-router --tailwind --add-ons shadcn ``` -### Create postcss.config.ts +### Add Components -Create a `postcss.config.ts` file at the root of your project. +You can now start adding components to your project. -```ts title="postcss.config.ts" showLineNumbers -export default { - plugins: { - "@tailwindcss/postcss": {}, - }, -} +```bash +npx shadcn@canary add button ``` -### Create `app/styles/app.css` +The command above will add the `Button` component to your project. You can then import it like this: -Create an `app.css` file in the `app/styles` directory and import `tailwindcss` +```tsx title="src/routes/index.tsx" showLineNumbers {3,12} +import { createFileRoute } from "@tanstack/react-router" -```css title="app/styles/app.css" -@import "tailwindcss" source("../"); -``` +import { Button } from "@/components/ui/button" -### Import `app.css` - -```tsx title="app/routes/__root.tsx" showLineNumbers {5,21-26} showLineNumbers -import type { ReactNode } from "react" -import { Outlet, createRootRoute } from "@tanstack/react-router" -import { Meta, Scripts } from "@tanstack/start" - -import appCss from "@/styles/app.css?url" - -export const Route = createRootRoute({ - head: () => ({ - meta: [ - { - charSet: "utf-8", - }, - { - name: "viewport", - content: "width=device-width, initial-scale=1", - }, - { - title: "TanStack Start Starter", - }, - ], - links: [ - { - rel: "stylesheet", - href: appCss, - }, - ], - }), - component: RootComponent, +export const Route = createFileRoute("/")({ + component: App, }) -``` - -### Edit tsconfig.json file - -Add the following code to the `tsconfig.json` file to resolve paths. - -```ts title="tsconfig.json" showLineNumbers {9-12} -{ - "compilerOptions": { - "jsx": "react-jsx", - "moduleResolution": "Bundler", - "module": "ESNext", - "target": "ES2022", - "skipLibCheck": true, - "strictNullChecks": true, - "baseUrl": ".", - "paths": { - "@/*": ["./app/*"] - } - } -} -``` - -### Run the CLI - -Run the `shadcn` init command to setup your project: - -```bash -npx shadcn@canary init -d -``` - -This will create a `components.json` file in the root of your project and configure CSS variables inside `app/styles/app.css`. - -### That's it - -You can now start adding components to your project. - -```bash -npx shadcn@canary add button -``` - -The command above will add the `Button` component to your project. You can then import it like this: - -```tsx title="app/routes/index.tsx" showLineNumbers {1,6} -import { Button } from "@/components/ui/button" - -function Home() { - const router = useRouter() - const state = Route.useLoaderData() - - return ( -
- -
- ) -} -``` - -
- -## Basic Starter - -The [Basic Starter](https://tanstack.com/start/latest/docs/framework/react/examples/start-basic) template has Tailwind v3 already configured. - - - -### Run the CLI - -Run the `shadcn` init command to setup your project: - -```bash -npx shadcn@canary init -d -``` - -This will create a `components.json` file in the root of your project and configure CSS variables inside `app/styles/app.css`. - -### That's it - -You can now start adding components to your project. - -```bash -npx shadcn@canary add button -``` - -The command above will add the `Button` component to your project. You can then import it like this: - -```tsx title="app/routes/index.tsx" showLineNumbers {1,6} -import { Button } from "@/components/ui/button" - -function Home() { - const router = useRouter() - const state = Route.useLoaderData() +function App() { return (
diff --git a/apps/www/content/docs/installation/vite.mdx b/apps/www/content/docs/installation/vite.mdx index 0a3a25ebc2..3be268bbaf 100644 --- a/apps/www/content/docs/installation/vite.mdx +++ b/apps/www/content/docs/installation/vite.mdx @@ -1,57 +1,28 @@ --- title: Vite -description: Install and configure Vite. +description: Install and configure shadcn/ui for Vite. --- - - **Update:** We have added full support for React 19 and Tailwind v4 in the - `canary` release. See the docs for [Tailwind v4](/docs/tailwind-v4) for more - information. - - ### Create project -Start by creating a new React project using `vite`: +Start by creating a new React project using `vite`. Select the **React + TypeScript** template: ```bash npm create vite@latest ``` -### Add Tailwind and its configuration - -Install `tailwindcss` and its peer dependencies, then generate your `tailwind.config.js` and `postcss.config.js` files: +### Add Tailwind CSS ```bash -npm install -D tailwindcss postcss autoprefixer +npm install tailwindcss @tailwindcss/vite ``` -```bash -npx tailwindcss init -p -``` +Replace everything in `src/index.css` with the following: -Add this import header in your main css file, `src/index.css` in our case: - -```css {1-3} showLineNumbers -@tailwind base; -@tailwind components; -@tailwind utilities; - -/* ... */ -``` - -Configure the tailwind template paths in `tailwind.config.js`: - -```js {3} -/** @type {import('tailwindcss').Config} */ -module.exports = { - content: ["./index.html", "./src/**/*.{ts,tsx,js,jsx}"], - theme: { - extend: {}, - }, - plugins: [], -} +```css title="src/index.css" +@import "tailwindcss"; ``` ### Edit tsconfig.json file @@ -107,13 +78,15 @@ Add the following code to the vite.config.ts so your app can resolve paths witho npm install -D @types/node ``` -```typescript +```typescript title="vite.config.ts" showLineNumbers {1,2,8-13} import path from "path" +import tailwindcss from "@tailwindcss/vite" import react from "@vitejs/plugin-react" import { defineConfig } from "vite" +// https://vite.dev/config/ export default defineConfig({ - plugins: [react()], + plugins: [react(), tailwindcss()], resolve: { alias: { "@": path.resolve(__dirname, "./src"), @@ -124,23 +97,19 @@ export default defineConfig({ ### Run the CLI -Run the `shadcn-ui` init command to setup your project: +Run the `shadcn` init command to setup your project: ```bash npx shadcn@latest init ``` -### Configure components.json +You will be asked a few questions to configure `components.json`. -You will be asked a few questions to configure `components.json`: - -```txt showLineNumbers -Which style would you like to use? › New York -Which color would you like to use as base color? › Zinc -Do you want to use CSS variables for colors? › no / yes +```txt +Which color would you like to use as base color? › Neutral ``` -### That's it +### Add Components You can now start adding components to your project. @@ -150,16 +119,18 @@ npx shadcn@latest add button The command above will add the `Button` component to your project. You can then import it like this: -```tsx {1,6} showLineNumbers +```tsx showLineNumbers title="src/App.tsx" import { Button } from "@/components/ui/button" -export default function Home() { +function App() { return ( -
+
) } + +export default App ``` diff --git a/apps/www/content/docs/tailwind-v4.mdx b/apps/www/content/docs/tailwind-v4.mdx index af7725bc48..a94b7ebcc5 100644 --- a/apps/www/content/docs/tailwind-v4.mdx +++ b/apps/www/content/docs/tailwind-v4.mdx @@ -1,21 +1,24 @@ --- -title: An update on Tailwind v4 -description: How to use shadcn/ui with Tailwind v4. +title: Tailwind v4 +description: How to use shadcn/ui with Tailwind v4 and React 19. --- -It’s here! Tailwind v4 and React 19. Ready for you to try out. It's available in the `canary` release of the CLI. You can start using it today. +It’s here! Tailwind v4 and React 19. Ready for you to try out. You can start using it today. -## TLDR - -If you're starting a new project with Tailwind v4 and React 19, use the `canary` version of the command-line: - -```bash -npx shadcn@canary init -``` + ## What's New -- The CLI (`canary`) can now initialize projects with Tailwind v4. +- The CLI can now initialize projects with Tailwind v4. - Full support for the new `@theme` directive and `@theme inline` option. - All components are updated for Tailwind v4 and React 19. - We’ve removed the forwardRefs and adjusted the types. @@ -24,133 +27,124 @@ npx shadcn@canary init - We're deprecating the `toast` component in favor of `sonner`. - Buttons now use the default cursor. - We're deprecating the `default` style. New projects will use `new-york`. +- HSL colors are now converted to OKLCH. **Note: this is non-breaking. Your existing apps with Tailwind v3 and React 18 will still work. When you add new components, they'll still be in v3 and React 18 until you upgrade. Only new projects start with Tailwind v4 and React 19.** -## What's Coming Next - -The following is still being worked on. I'll post updates soon. - -- Migrating colors to OKLCH. -- Fix and improve animations. - ## See it Live I put together a demo with all the updated components here: https://v4.shadcn.com -Take a look and test the components. If you find any bugs, leave a comment on the [GitHub issue](https://github.com/shadcn-ui/ui/issues/6585). - -- The code for the app is here: https://github.com/shadcn-ui/ui/tree/main/apps/v4 -- The v4 components can be found here: https://github.com/shadcn-ui/ui/tree/main/apps/v4/registry/new-york-v4/ui +Take a look and test the components. If you find any bugs, please let me know on [GitHub](https://github.com/shadcn-ui/ui). ## Try It Out -You can test Tailwind v4 + React 19 today using the `canary` release of the CLI. +You can test Tailwind v4 + React 19 today using the `canary` release of the CLI. See the framework specific guides below for how to get started. -```bash -pnpm dlx shadcn@canary init -``` - -I'm still working on the docs, but here's a quick guide to testing new projects: - -### Next.js - -1. Start a new project with Tailwind v4 and React 19: - -```bash -pnpm create next-app@canary --tailwind --eslint --typescript --app --no-src-dir -``` - -2. Init shadcn/ui. This will create your `components.json` and set up your CSS variables: - -```bash -pnpm dlx shadcn@canary init -``` - -3. You should now be able to add components: - -```bash -pnpm dlx shadcn@canary add button -``` - -### Vite - -1. Create a new project with React 19: - -```bash -pnpm create vite --template=react-ts -``` - -2. Follow the official guide to add Tailwind CSS: https://tailwindcss.com/docs/installation/using-vite - -3. Add path aliases to `tsconfig.json`: - -```json title="tsconfig.json" showLineNumbers -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ], - "compilerOptions": { - "baseUrl": ".", - "paths": { - "@/*": ["./src/*"] - } - } -} -``` - -4. Add path aliases to `tsconfig.app.json`: - -```json title="tsconfig.app.json" showLineNumbers -{ - "compilerOptions": { - "baseUrl": ".", - "paths": { - "@/*": ["./src/*"] - } - } -} -``` - -5. Install `@types/node`: - -```bash -pnpm add -D @types/node -``` - -6. Add resolve alias config to `vite.config.ts`: - -```ts title="vite.config.ts" showLineNumbers -import path from "path" -import tailwindcss from "@tailwindcss/vite" -import react from "@vitejs/plugin-react" -import { defineConfig } from "vite" - -export default defineConfig({ - plugins: [react(), tailwindcss()], - resolve: { - alias: { - "@": path.resolve(__dirname, "./src"), - }, - }, -}) -``` - -7. Init `shadcn/ui`. This will create your `components.json` and set up your CSS variables: - -```bash -pnpm dlx shadcn@canary init -``` - -8. You should now be able to add components: - -```bash -pnpm dlx shadcn@canary add button -``` - -(Note: If you need help with other frameworks, drop a comment below. I'll update the guide) +
+ + + Next.js + + +

Next.js

+
+ + + Vite + + +

Vite

+
+ + + + +

Laravel

+
+ + + + +

React Router

+
+ + + Astro + + +

Astro

+
+ + + + +

TanStack Start

+
+ + + Gatsby + + +

Gatsby

+
+ + + React + + +

Manual

+
+
## Upgrade Your Project diff --git a/apps/www/content/docs/theming.mdx b/apps/www/content/docs/theming.mdx index bb168de19e..d1fe1c40a4 100644 --- a/apps/www/content/docs/theming.mdx +++ b/apps/www/content/docs/theming.mdx @@ -1,34 +1,9 @@ --- title: Theming -description: Using CSS Variables or Tailwind CSS for theming. +description: Using CSS Variables and color utilities for theming. --- -You can choose between using CSS variables or Tailwind CSS utility classes for theming. - -## Utility classes - -```tsx /bg-zinc-950/ /text-zinc-50/ /dark:bg-white/ /dark:text-zinc-950/ -
-``` - -To use utility classes for theming set `tailwind.cssVariables` to `false` in your `components.json` file. - -```json {8} title="components.json" -{ - "style": "default", - "rsc": true, - "tailwind": { - "config": "tailwind.config.js", - "css": "app/globals.css", - "baseColor": "slate", - "cssVariables": false - }, - "aliases": { - "components": "@/components", - "utils": "@/lib/utils" - } -} -``` +You can choose between using CSS variables (recommended) or utility classes for theming. ## CSS Variables @@ -43,19 +18,52 @@ To use CSS variables for theming set `tailwind.cssVariables` to `true` in your ` "style": "default", "rsc": true, "tailwind": { - "config": "tailwind.config.js", + "config": "", "css": "app/globals.css", - "baseColor": "slate", + "baseColor": "neutral", "cssVariables": true }, "aliases": { "components": "@/components", - "utils": "@/lib/utils" - } + "utils": "@/lib/utils", + "ui": "@/registry/new-york-v4/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "iconLibrary": "lucide" } ``` -### Convention +## Utility classes + +```tsx /bg-zinc-950/ /text-zinc-50/ /dark:bg-white/ /dark:text-zinc-950/ +
+``` + +To use utility classes for theming set `tailwind.cssVariables` to `false` in your `components.json` file. + +```json {8} title="components.json" +{ + "style": "default", + "rsc": true, + "tailwind": { + "config": "", + "css": "app/globals.css", + "baseColor": "slate", + "cssVariables": false + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/registry/new-york-v4/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "iconLibrary": "lucide" +} +``` + +## Convention We use a simple `background` and `foreground` convention for colors. The `background` variable is used for the background color of the component and the `foreground` variable is used for the text color. @@ -68,112 +76,111 @@ The `background` suffix is omitted when the variable is used for the background Given the following CSS variables: ```css ---primary: 222.2 47.4% 11.2%; ---primary-foreground: 210 40% 98%; +--primary: oklch(0.205 0 0); +--primary-foreground: oklch(0.985 0 0); ``` -The `background` color of the following component will be `hsl(var(--primary))` and the `foreground` color will be `hsl(var(--primary-foreground))`. +The `background` color of the following component will be `var(--primary)` and the `foreground` color will be `var(--primary-foreground)`. ```tsx
Hello
``` - - -**CSS variables must be defined without color space function**. See the [Tailwind CSS documentation](https://tailwindcss.com/docs/customizing-colors#using-css-variables) for more information. - - - -### List of variables +## List of variables Here's the list of variables available for customization: - +```css title="app/globals.css" +:root { + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --destructive-foreground: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --radius: 0.625rem; + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); +} -```css title="Default background color of ...etc" ---background: 0 0% 100%; ---foreground: 222.2 47.4% 11.2%; +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.145 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.145 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.985 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.396 0.141 25.723); + --destructive-foreground: oklch(0.637 0.237 25.331); + --border: oklch(0.269 0 0); + --input: oklch(0.269 0 0); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(0.269 0 0); + --sidebar-ring: oklch(0.439 0 0); +} ``` -```css title="Muted backgrounds such as , and " ---muted: 210 40% 96.1%; ---muted-foreground: 215.4 16.3% 46.9%; -``` - -```css title="Background color for " ---card: 0 0% 100%; ---card-foreground: 222.2 47.4% 11.2%; -``` - -```css title="Background color for popovers such as , , " ---popover: 0 0% 100%; ---popover-foreground: 222.2 47.4% 11.2%; -``` - -```css title="Default border color" ---border: 214.3 31.8% 91.4%; -``` - -```css title="Border color for inputs such as ,