Changelog
Latest updates and announcements.
Sep 2024 - New Components
Navigation Menu
A collection of links for navigating websites.
import { siteConfig } from "@/config/site";
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuDescription,
NavigationMenuItem,
NavigationMenuItemLabel,
NavigationMenuLink,
NavigationMenuTrigger,
} from "@repo/tailwindcss/ui/navigation-menu";
import type { ParentProps } from "solid-js";
import { For } from "solid-js";
const ListItem = (props: ParentProps<{ title: string; href: string }>) => {
return (
<NavigationMenuLink
href={props.href}
class="block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-[box-shadow,background-color] duration-200 hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground focus-visible:outline-none focus-visible:ring-[1.5px] focus-visible:ring-ring"
>
<NavigationMenuItemLabel class="text-sm font-medium leading-none">
{props.title}
</NavigationMenuItemLabel>
<NavigationMenuDescription class="line-clamp-2 text-sm leading-snug text-muted-foreground">
{props.children}
</NavigationMenuDescription>
</NavigationMenuLink>
);
};
const components: { title: string; href: string; description: string }[] = [
{
title: "Data Table",
href: "/docs/components/data-table",
description: "Powerful table and datagrids built using TanStack Table.",
},
{
title: "Date Picker",
href: "/docs/components/date-picker",
description:
"A component that allows users to select a date from a calendar.",
},
{
title: "OTP Field",
href: "/docs/components/otp-field",
description: "An accessible and customizable OTP Input component.",
},
{
title: "Resizable",
href: "/docs/components/resizable",
description:
"A component that divides your interface into resizable sections.",
},
{
title: "Sonner",
href: "/docs/components/sonner",
description: "An opinionated toast component for Solid.",
},
{
title: "Toggle Group",
href: "/docs/components/toggle-group",
description:
"A set of two-state buttons that can be toggled on (pressed) or off (not pressed).",
},
];
const NavigationMenuDemo = () => {
return (
<NavigationMenu>
<NavigationMenuItem>
<NavigationMenuTrigger class="transition-[box-shadow,background-color] focus-visible:outline-none focus-visible:ring-[1.5px] focus-visible:ring-ring data-[expanded]:bg-accent">
Learn
</NavigationMenuTrigger>
<NavigationMenuContent class="grid gap-3 p-4 w-[400px] lg:w-[500px] lg:grid-cols-[.75fr_1fr] [&>li:first-of-type]:row-span-3">
<NavigationMenuLink
href="/"
class="flex h-full w-full select-none flex-col justify-end rounded-md bg-gradient-to-b from-muted/50 to-muted p-6 no-underline outline-none transition-shadow duration-200 hover:shadow-md focus-visible:shadow-md focus-visible:ring-[1.5px] focus-visible:ring-ring"
>
<NavigationMenuItemLabel class="mb-2 mt-4 text-lg font-medium">
{siteConfig.title}
</NavigationMenuItemLabel>
<NavigationMenuDescription class="text-sm leading-tight text-muted-foreground">
{siteConfig.description}
</NavigationMenuDescription>
</NavigationMenuLink>
<ListItem href="/docs" title="Introduction">
{siteConfig.description}.
</ListItem>
<ListItem href="/docs/installation" title="Installation">
How to install dependencies and structure your app.
</ListItem>
<ListItem href="/docs/components/typography" title="Typography">
Styles for headings, paragraphs, lists...etc.
</ListItem>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuTrigger class="transition-[box-shadow,background-color] focus-visible:outline-none focus-visible:ring-1.5px focus-visible:ring-ring data-[expanded]:bg-accent">
Overview
</NavigationMenuTrigger>
<NavigationMenuContent class="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px]">
<For each={components}>
{(item) => (
<ListItem href={item.href} title={item.title}>
{item.description}
</ListItem>
)}
</For>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuTrigger
as="a"
href="/docs"
class="transition-[box-shadow,background-color] focus-visible:outline-none focus-visible:ring-[1.5px] focus-visible:ring-ring data-[expanded]:bg-accent"
>
Documentation
</NavigationMenuTrigger>
</NavigationMenu>
);
};
export default NavigationMenuDemo;
Jun 2024 - New components
Number Field
A number input that allow users to input custom number entries with a keyboard.
import {
NumberField,
NumberFieldDecrementTrigger,
NumberFieldGroup,
NumberFieldIncrementTrigger,
NumberFieldInput,
NumberFieldLabel,
} from "@repo/tailwindcss/ui/number-field";
const NumberFieldDemo = () => {
const thisYear = () => new Date(Date.now()).getUTCFullYear();
const age = () => thisYear() - 2001;
return (
<NumberField defaultValue={age()} minValue={0}>
<NumberFieldLabel>Age</NumberFieldLabel>
<NumberFieldGroup>
<NumberFieldDecrementTrigger aria-label="Decrement" />
<NumberFieldInput />
<NumberFieldIncrementTrigger aria-label="Increment" />
</NumberFieldGroup>
</NumberField>
);
};
export default NumberFieldDemo;
OTP Field
A fully featured OTP input component. Support all default keybindings and is accessible, Android and iOS copy, paste, cut and many more. Built on top of @corvu/otp-field
. An awesome work from Jasmin.
import {
OTPField,
OTPFieldGroup,
OTPFieldInput,
OTPFieldSeparator,
OTPFieldSlot,
} from "@repo/tailwindcss/ui/otp-field";
const OtpFieldDemo = () => {
return (
<OTPField maxLength={6}>
<OTPFieldInput />
<OTPFieldGroup>
<OTPFieldSlot index={0} />
<OTPFieldSlot index={1} />
<OTPFieldSlot index={2} />
</OTPFieldGroup>
<OTPFieldSeparator />
<OTPFieldGroup>
<OTPFieldSlot index={3} />
<OTPFieldSlot index={4} />
<OTPFieldSlot index={5} />
</OTPFieldGroup>
</OTPField>
);
};
export default OtpFieldDemo;
Menubar
A visually persistent menu common in desktop applications that provides quick access to a consistent set of commands.
import {
Menubar,
MenubarCheckboxItem,
MenubarContent,
MenubarItem,
MenubarMenu,
MenubarRadioGroup,
MenubarRadioItem,
MenubarSeparator,
MenubarShortcut,
MenubarSub,
MenubarSubContent,
MenubarSubTrigger,
MenubarTrigger,
} from "@repo/tailwindcss/ui/menubar";
const MenubarDemo = () => {
return (
<Menubar>
<MenubarMenu>
<MenubarTrigger>File</MenubarTrigger>
<MenubarContent>
<MenubarItem>
New Tab <MenubarShortcut>⌘T</MenubarShortcut>
</MenubarItem>
<MenubarItem>
New Window <MenubarShortcut>⌘N</MenubarShortcut>
</MenubarItem>
<MenubarItem disabled>New Incognito Window</MenubarItem>
<MenubarSeparator />
<MenubarSub>
<MenubarSubTrigger>Share</MenubarSubTrigger>
<MenubarSubContent>
<MenubarItem>Email link</MenubarItem>
<MenubarItem>Messages</MenubarItem>
<MenubarItem>Notes</MenubarItem>
</MenubarSubContent>
</MenubarSub>
<MenubarSeparator />
<MenubarItem>
Print... <MenubarShortcut>⌘P</MenubarShortcut>
</MenubarItem>
</MenubarContent>
</MenubarMenu>
<MenubarMenu>
<MenubarTrigger>Edit</MenubarTrigger>
<MenubarContent>
<MenubarItem>
Undo <MenubarShortcut>⌘Z</MenubarShortcut>
</MenubarItem>
<MenubarItem>
Redo <MenubarShortcut>⇧⌘Z</MenubarShortcut>
</MenubarItem>
<MenubarSeparator />
<MenubarSub>
<MenubarSubTrigger>Find</MenubarSubTrigger>
<MenubarSubContent>
<MenubarItem>Search the web</MenubarItem>
<MenubarSeparator />
<MenubarItem>Find...</MenubarItem>
<MenubarItem>Find Next</MenubarItem>
<MenubarItem>Find Previous</MenubarItem>
</MenubarSubContent>
</MenubarSub>
<MenubarSeparator />
<MenubarItem>Cut</MenubarItem>
<MenubarItem>Copy</MenubarItem>
<MenubarItem>Paste</MenubarItem>
</MenubarContent>
</MenubarMenu>
<MenubarMenu>
<MenubarTrigger>View</MenubarTrigger>
<MenubarContent>
<MenubarCheckboxItem>Always Show Bookmarks Bar</MenubarCheckboxItem>
<MenubarCheckboxItem checked>
Always Show Full URLs
</MenubarCheckboxItem>
<MenubarSeparator />
<MenubarItem inset>
Reload <MenubarShortcut>⌘R</MenubarShortcut>
</MenubarItem>
<MenubarItem disabled inset>
Force Reload <MenubarShortcut>⇧⌘R</MenubarShortcut>
</MenubarItem>
<MenubarSeparator />
<MenubarItem inset>Toggle Fullscreen</MenubarItem>
<MenubarSeparator />
<MenubarItem inset>Hide Sidebar</MenubarItem>
</MenubarContent>
</MenubarMenu>
<MenubarMenu>
<MenubarTrigger>Profiles</MenubarTrigger>
<MenubarContent>
<MenubarRadioGroup value="benoit">
<MenubarRadioItem value="andy">Andy</MenubarRadioItem>
<MenubarRadioItem value="benoit">Benoit</MenubarRadioItem>
<MenubarRadioItem value="Luis">Luis</MenubarRadioItem>
</MenubarRadioGroup>
<MenubarSeparator />
<MenubarItem inset>Edit...</MenubarItem>
<MenubarSeparator />
<MenubarItem inset>Add Profile...</MenubarItem>
</MenubarContent>
</MenubarMenu>
</Menubar>
);
};
export default MenubarDemo;
Calendar
New Calendar
demo.
import {
DatePicker,
DatePickerContent,
DatePickerContext,
DatePickerRangeText,
DatePickerTable,
DatePickerTableBody,
DatePickerTableCell,
DatePickerTableCellTrigger,
DatePickerTableHead,
DatePickerTableHeader,
DatePickerTableRow,
DatePickerView,
DatePickerViewControl,
DatePickerViewTrigger,
} from "@repo/tailwindcss/ui/date-picker";
import { For } from "solid-js";
const CalendarDemo = () => {
return (
<DatePicker open>
<DatePickerContent>
<DatePickerView view="day">
<DatePickerContext>
{(context) => (
<>
<DatePickerViewControl>
<DatePickerViewTrigger>
<DatePickerRangeText />
</DatePickerViewTrigger>
</DatePickerViewControl>
<DatePickerTable>
<DatePickerTableHead>
<DatePickerTableRow>
<For each={context().weekDays}>
{(weekDay) => (
<DatePickerTableHeader>
{weekDay.short}
</DatePickerTableHeader>
)}
</For>
</DatePickerTableRow>
</DatePickerTableHead>
<DatePickerTableBody>
<For each={context().weeks}>
{(week) => (
<DatePickerTableRow>
<For each={week}>
{(day) => (
<DatePickerTableCell value={day}>
<DatePickerTableCellTrigger>
{day.day}
</DatePickerTableCellTrigger>
</DatePickerTableCell>
)}
</For>
</DatePickerTableRow>
)}
</For>
</DatePickerTableBody>
</DatePickerTable>
</>
)}
</DatePickerContext>
</DatePickerView>
<DatePickerView view="month">
<DatePickerContext>
{(context) => (
<>
<DatePickerViewControl>
<DatePickerViewTrigger>
<DatePickerRangeText />
</DatePickerViewTrigger>
</DatePickerViewControl>
<DatePickerTable>
<DatePickerTableBody>
<For
each={context().getMonthsGrid({
columns: 4,
format: "short",
})}
>
{(months) => (
<DatePickerTableRow>
<For each={months}>
{(month) => (
<DatePickerTableCell value={month.value}>
<DatePickerTableCellTrigger>
{month.label}
</DatePickerTableCellTrigger>
</DatePickerTableCell>
)}
</For>
</DatePickerTableRow>
)}
</For>
</DatePickerTableBody>
</DatePickerTable>
</>
)}
</DatePickerContext>
</DatePickerView>
<DatePickerView view="year">
<DatePickerContext>
{(context) => (
<>
<DatePickerViewControl>
<DatePickerViewTrigger>
<DatePickerRangeText />
</DatePickerViewTrigger>
</DatePickerViewControl>
<DatePickerTable>
<DatePickerTableBody>
<For
each={context().getYearsGrid({
columns: 4,
})}
>
{(years) => (
<DatePickerTableRow>
<For each={years}>
{(year) => (
<DatePickerTableCell value={year.value}>
<DatePickerTableCellTrigger>
{year.label}
</DatePickerTableCellTrigger>
</DatePickerTableCell>
)}
</For>
</DatePickerTableRow>
)}
</For>
</DatePickerTableBody>
</DatePickerTable>
</>
)}
</DatePickerContext>
</DatePickerView>
</DatePickerContent>
</DatePicker>
);
};
export default CalendarDemo;
May 2024 - CLI and components update
CLI Updates
diff
Track upstream component updates with diff
.
Run the diff
command to get a list of components that have updates available:
npx shadcn-solid diff
┌ shadcn-solid
│
◇ The following components have updates avaiable
│
● alert - path\to\my-ap\components\ui\alert.tsx
│
● card - path\to\my-ap\components\ui\card.tsx
│
└ Run diff <component> to see the changes
Then run diff [component]
to see the changes:
npx shadcn-solid diff alert
const alertVariants = cva(
- "relative w-full rounded-lg border",
+ "relative w-full pl-12 rounded-lg border"
)
add
Adding multiple components or using —all is significantly faster
Schema update
The components.json
schema has been updated
{
"$schema": "https://shadcn-solid.com/schema.json",
"tailwind": {
"config": "tailwind.config.cjs",
"css": {
"path": "src/app.css",
"variable": true
},
"color": "slate",
"prefix": ""
},
"alias": {
"component": "@/components",
"cn": "@/libs/cn"
}
}
Component updates
We’ve added new components to shadcn-solid.
- Toggle Group - A set of two-state buttons that can be toggled on (pressed) or off (not pressed).
- Sonner - An opinionated toast component for Solid.
Toggle Group
import {
ToggleGroup,
ToggleGroupItem,
} from "@repo/tailwindcss/ui/toggle-group";
const ToggleGroupDemo = () => {
return (
<ToggleGroup multiple>
<ToggleGroupItem value="bold" aria-label="Toggle bold">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4"
viewBox="0 0 24 24"
>
<path
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M7 5h6a3.5 3.5 0 0 1 0 7H7zm6 7h1a3.5 3.5 0 0 1 0 7H7v-7"
/>
</svg>
</ToggleGroupItem>
<ToggleGroupItem value="italic" aria-label="Toggle italic">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4"
viewBox="0 0 24 24"
>
<path
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M11 5h6M7 19h6m1-14l-4 14"
/>
</svg>
</ToggleGroupItem>
<ToggleGroupItem value="strikethrough" aria-label="Toggle strikethrough">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4"
viewBox="0 0 24 24"
>
<path
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M7 5v5a5 5 0 0 0 10 0V5M5 19h14"
/>
</svg>
</ToggleGroupItem>
</ToggleGroup>
);
};
export default ToggleGroupDemo;
Sonner
import { Button } from "@repo/tailwindcss/ui/button";
import { toast } from "solid-sonner";
const SonnerDemo = () => {
return (
<Button
variant="outline"
onClick={() =>
toast("Event has been created", {
description: "Sunday, December 03, 2023 at 9:00 AM",
action: {
label: "Undo",
onClick: () => console.log("Undo"),
},
})
}
>
Show Toast
</Button>
);
};
export default SonnerDemo;
Transitioned two existing components, Splitter and Command, to utilize the new Resizable from corvu and the solid port of cmdk, respectively.
April 2024 - UnoCSS.
We’re excited to announce support for UnoCSS, an instant atomic CSS engine.
Framework selection
You can select your preferred CSS framework during project setup using the init
command:
◆ Which CSS framework would you like to use?
│ ○ TailwindCSS
│ ● UnoCSS
Component installation
A new --all
option has been added to the add
command. This enhancement simplifies installing all available components in one go.
March 2024 - Drawer.
- Drawer - A draggable dialog that is attached to any side of the viewport.
Drawer
Built on top of Drawer component from Corvu.
March 2024 - Updated docs, UI, and fixed bugs.
- Update style for Date Picker.
- Updated documentation for Toggle and Toast.
- Fixed focus issue with Checkbox.
- Resolved duplication problem occurring with Toast.
- Corrected styling for Tabs.
February 2024 - New components, CLI and more
We’ve added new components to shadcn-solid and made a improvements to the CLI.
Here’s a quick overview of what’s new:
- Carousel - A carousel component with motion, swipe gestures and keyboard support.
- Pagination - A pagination component allows the user to select a specific page from a range of pages.
- Command - A Composable command menu component.
- Date Picker - A component that allows users to select a date from a calendar.
- CLI updates - Support for custom Tailwind prefix, remove
style
and more.
Date Picker
import {
DatePicker,
DatePickerContent,
DatePickerContext,
DatePickerControl,
DatePickerInput,
DatePickerPositioner,
DatePickerRangeText,
DatePickerTable,
DatePickerTableBody,
DatePickerTableCell,
DatePickerTableCellTrigger,
DatePickerTableHead,
DatePickerTableHeader,
DatePickerTableRow,
DatePickerTrigger,
DatePickerView,
DatePickerViewControl,
DatePickerViewTrigger,
} from "@repo/tailwindcss/ui/date-picker";
import { Index } from "solid-js";
import { Portal } from "solid-js/web";
const DatePickerDemo = () => {
return (
<DatePicker>
<DatePickerControl>
<DatePickerInput />
<DatePickerTrigger />
</DatePickerControl>
<Portal>
<DatePickerPositioner>
<DatePickerContent>
<DatePickerView view="day">
<DatePickerContext>
{(context) => (
<>
<DatePickerViewControl>
<DatePickerViewTrigger>
<DatePickerRangeText />
</DatePickerViewTrigger>
</DatePickerViewControl>
<DatePickerTable>
<DatePickerTableHead>
<DatePickerTableRow>
<Index each={context().weekDays}>
{(weekDay) => (
<DatePickerTableHeader>
{weekDay().short}
</DatePickerTableHeader>
)}
</Index>
</DatePickerTableRow>
</DatePickerTableHead>
<DatePickerTableBody>
<Index each={context().weeks}>
{(week) => (
<DatePickerTableRow>
<Index each={week()}>
{(day) => (
<DatePickerTableCell value={day()}>
<DatePickerTableCellTrigger>
{day().day}
</DatePickerTableCellTrigger>
</DatePickerTableCell>
)}
</Index>
</DatePickerTableRow>
)}
</Index>
</DatePickerTableBody>
</DatePickerTable>
</>
)}
</DatePickerContext>
</DatePickerView>
<DatePickerView view="month">
<DatePickerContext>
{(context) => (
<>
<DatePickerViewControl>
<DatePickerViewTrigger>
<DatePickerRangeText />
</DatePickerViewTrigger>
</DatePickerViewControl>
<DatePickerTable>
<DatePickerTableBody>
<Index
each={context().getMonthsGrid({
columns: 4,
format: "short",
})}
>
{(months) => (
<DatePickerTableRow>
<Index each={months()}>
{(month) => (
<DatePickerTableCell value={month().value}>
<DatePickerTableCellTrigger>
{month().label}
</DatePickerTableCellTrigger>
</DatePickerTableCell>
)}
</Index>
</DatePickerTableRow>
)}
</Index>
</DatePickerTableBody>
</DatePickerTable>
</>
)}
</DatePickerContext>
</DatePickerView>
<DatePickerView view="year">
<DatePickerContext>
{(context) => (
<>
<DatePickerViewControl>
<DatePickerViewTrigger>
<DatePickerRangeText />
</DatePickerViewTrigger>
</DatePickerViewControl>
<DatePickerTable>
<DatePickerTableBody>
<Index
each={context().getYearsGrid({
columns: 4,
})}
>
{(years) => (
<DatePickerTableRow>
<Index each={years()}>
{(year) => (
<DatePickerTableCell value={year().value}>
<DatePickerTableCellTrigger>
{year().label}
</DatePickerTableCellTrigger>
</DatePickerTableCell>
)}
</Index>
</DatePickerTableRow>
)}
</Index>
</DatePickerTableBody>
</DatePickerTable>
</>
)}
</DatePickerContext>
</DatePickerView>
</DatePickerContent>
</DatePickerPositioner>
</Portal>
</DatePicker>
);
};
export default DatePickerDemo;
Command
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
CommandShortcut,
} from "@repo/tailwindcss/ui/command";
import { For, type JSXElement } from "solid-js";
type Option = {
icon: JSXElement;
label: string;
disabled: boolean;
shortcut?: JSXElement;
};
type List = {
label: string;
options: Option[];
};
export const commandData: List[] = [
{
label: "Suggestions",
options: [
{
icon: (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
class="mr-2 h-4 w-4"
>
<path
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4 7a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2zm12-4v4M8 3v4m-4 4h16m-9 4h1m0 0v3"
/>
</svg>
),
label: "Calendar",
disabled: false,
},
{
icon: (
<svg
xmlns="http://www.w3.org/2000/svg"
class="mr-2 h-4 w-4"
viewBox="0 0 24 24"
>
<g
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
>
<path d="M3 12a9 9 0 1 0 18 0a9 9 0 1 0-18 0m6-2h.01M15 10h.01" />
<path d="M9.5 15a3.5 3.5 0 0 0 5 0" />
</g>
</svg>
),
label: "Search emoji",
disabled: false,
},
{
icon: (
<svg
xmlns="http://www.w3.org/2000/svg"
class="mr-2 h-4 w-4"
viewBox="0 0 24 24"
>
<g
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
>
<path d="M4 13a8 8 0 0 1 7 7a6 6 0 0 0 3-5a9 9 0 0 0 6-8a3 3 0 0 0-3-3a9 9 0 0 0-8 6a6 6 0 0 0-5 3" />
<path d="M7 14a6 6 0 0 0-3 6a6 6 0 0 0 6-3m4-8a1 1 0 1 0 2 0a1 1 0 1 0-2 0" />
</g>
</svg>
),
label: "Launch",
disabled: false,
},
],
},
{
label: "Settings",
options: [
{
icon: (
<svg
xmlns="http://www.w3.org/2000/svg"
class="mr-2 h-4 w-4"
viewBox="0 0 24 24"
>
<path
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M8 7a4 4 0 1 0 8 0a4 4 0 0 0-8 0M6 21v-2a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v2"
/>
</svg>
),
label: "Profile",
disabled: true,
shortcut: <CommandShortcut>⌘P</CommandShortcut>,
},
{
icon: (
<svg
xmlns="http://www.w3.org/2000/svg"
class="mr-2 h-4 w-4"
viewBox="0 0 24 24"
>
<g
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
>
<path d="M3 7a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
<path d="m3 7l9 6l9-6" />
</g>
</svg>
),
label: "Mail",
disabled: false,
shortcut: <CommandShortcut>⌘B</CommandShortcut>,
},
{
icon: (
<svg
xmlns="http://www.w3.org/2000/svg"
class="mr-2 h-4 w-4"
viewBox="0 0 24 24"
>
<g
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
>
<path d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 0 0-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 0 0-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 0 0-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 0 0-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 0 0 1.066-2.573c-.94-1.543.826-3.31 2.37-2.37c1 .608 2.296.07 2.572-1.065" />
<path d="M9 12a3 3 0 1 0 6 0a3 3 0 0 0-6 0" />
</g>
</svg>
),
label: "Setting",
disabled: false,
shortcut: <CommandShortcut>⌘S</CommandShortcut>,
},
],
},
];
const CommandDemo = () => {
return (
<Command class="rounded-lg border shadow-md">
<CommandInput placeholder="Type a command or search..." />
<CommandList>
<CommandEmpty>No results found.</CommandEmpty>
<For each={commandData}>
{(item) => (
<CommandGroup heading={item.label}>
<For each={item.options}>
{(item) => (
<CommandItem disabled={item.disabled}>
{item.icon}
<span>{item.label}</span>
{item.shortcut}
</CommandItem>
)}
</For>
</CommandGroup>
)}
</For>
</CommandList>
</Command>
);
};
export default CommandDemo;
Carousel
We’ve added a fully featured carousel component with motion, swipe gestures and keyboard support. Built on top of Embla Carousel.
It has support for infinite looping, autoplay, vertical orientation, and more.
import { Card, CardContent } from "@repo/tailwindcss/ui/card";
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNext,
CarouselPrevious,
} from "@repo/tailwindcss/ui/carousel";
import { Index } from "solid-js";
const CarouselDemo = () => {
return (
<Carousel class="w-full max-w-xs">
<CarouselContent>
<Index each={Array.from({ length: 5 })}>
{(_, index) => (
<CarouselItem>
<div class="p-1">
<Card>
<CardContent class="flex aspect-square items-center justify-center p-6">
<span class="text-4xl font-semibold">{index + 1}</span>
</CardContent>
</Card>
</div>
</CarouselItem>
)}
</Index>
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel>
);
};
export default CarouselDemo;
Pagination
We’ve added a pagination component with page navigation, previous and next buttons. Simple and flexible.
import {
Pagination,
PaginationEllipsis,
PaginationItem,
PaginationItems,
PaginationNext,
PaginationPrevious,
} from "@repo/tailwindcss/ui/pagination";
const PaginationDemo = () => {
return (
<Pagination
fixedItems
count={10}
itemComponent={(props) => (
<PaginationItem page={props.page}>{props.page}</PaginationItem>
)}
ellipsisComponent={() => <PaginationEllipsis />}
>
<PaginationPrevious />
<PaginationItems />
<PaginationNext />
</Pagination>
);
};
export default PaginationDemo;
CLI updates
-
Icon library
We’re removed the icon library and using SVG for more flexibility.
-
Remove
style
propertyIn this update, the
style
property has been removed, but there’s a possibility of its return if additional styling features are introduced in future updates. -
Support custom ui dir
You can use this config to customize the installation directory for your
ui
components.components.json { "aliases": { "ui": "@/ui" } }
-
Support custom Tailwind prefix
You can now configure a custom Tailwind prefix and the cli will automatically prefix your utility classes when adding components.
A drop-in for your existing design system with no conflict. 🔥
<AlertDialog class="tw-grid tw-gap-4 tw-border tw-bg-background tw-shadow-lg" />
It works with
cn
,cva
and CSS variables.
That’s it. Happy Lunar New Year.