Changelog
Latest updates and announcements.
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/default/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;
import {
NumberField,
NumberFieldDecrementTrigger,
NumberFieldGroup,
NumberFieldIncrementTrigger,
NumberFieldInput,
NumberFieldLabel,
} from "@repo/tailwindcss/solid/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/default/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;
import {
OTPField,
OTPFieldGroup,
OTPFieldInput,
OTPFieldSeparator,
OTPFieldSlot,
} from "@repo/tailwindcss/solid/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/default/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;
import {
Menubar,
MenubarCheckboxItem,
MenubarContent,
MenubarItem,
MenubarMenu,
MenubarRadioGroup,
MenubarRadioItem,
MenubarSeparator,
MenubarShortcut,
MenubarSub,
MenubarSubContent,
MenubarSubTrigger,
MenubarTrigger,
} from "@repo/tailwindcss/solid/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,
DatePickerContext,
DatePickerRangeText,
DatePickerTable,
DatePickerTableBody,
DatePickerTableCell,
DatePickerTableCellTrigger,
DatePickerTableHead,
DatePickerTableHeader,
DatePickerTableRow,
DatePickerView,
DatePickerViewControl,
DatePickerViewTrigger,
} from "@repo/tailwindcss/default/date-picker";
import { For } from "solid-js";
const CalendarDemo = () => {
return (
<DatePicker open closeOnSelect={false}>
<div class="rounded-md border bg-popover p-3 text-popover-foreground">
<DatePickerView view="day">
<DatePickerContext>
{(api) => (
<>
<DatePickerViewControl>
<DatePickerViewTrigger>
<DatePickerRangeText />
</DatePickerViewTrigger>
</DatePickerViewControl>
<DatePickerTable>
<DatePickerTableHead>
<DatePickerTableRow>
<For each={api().weekDays}>
{(weekDay) => (
<DatePickerTableHeader>
{weekDay.short}
</DatePickerTableHeader>
)}
</For>
</DatePickerTableRow>
</DatePickerTableHead>
<DatePickerTableBody>
<For each={api().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"
class="w-[calc(var(--preference-width)-(0.75rem*2))]"
>
<DatePickerContext>
{(api) => (
<>
<DatePickerViewControl>
<DatePickerViewTrigger>
<DatePickerRangeText />
</DatePickerViewTrigger>
</DatePickerViewControl>
<DatePickerTable>
<DatePickerTableBody>
<For
each={api().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"
class="w-[calc(var(--preference-width)-(0.75rem*2))]"
>
<DatePickerContext>
{(api) => (
<>
<DatePickerViewControl>
<DatePickerViewTrigger>
<DatePickerRangeText />
</DatePickerViewTrigger>
</DatePickerViewControl>
<DatePickerTable>
<DatePickerTableBody>
<For
each={api().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>
</div>
</DatePicker>
);
};
export default CalendarDemo;
import {
DatePicker,
DatePickerContext,
DatePickerRangeText,
DatePickerTable,
DatePickerTableBody,
DatePickerTableCell,
DatePickerTableCellTrigger,
DatePickerTableHead,
DatePickerTableHeader,
DatePickerTableRow,
DatePickerView,
DatePickerViewControl,
DatePickerViewTrigger,
} from "@repo/tailwindcss/solid/date-picker";
import { For } from "solid-js";
const CalendarDemo = () => {
return (
<DatePicker open closeOnSelect={false}>
<div class="rounded-md border bg-popover p-3 text-popover-foreground">
<DatePickerView view="day">
<DatePickerContext>
{(api) => (
<>
<DatePickerViewControl>
<DatePickerViewTrigger>
<DatePickerRangeText />
</DatePickerViewTrigger>
</DatePickerViewControl>
<DatePickerTable>
<DatePickerTableHead>
<DatePickerTableRow>
<For each={api().weekDays}>
{(weekDay) => (
<DatePickerTableHeader>
{weekDay.short}
</DatePickerTableHeader>
)}
</For>
</DatePickerTableRow>
</DatePickerTableHead>
<DatePickerTableBody>
<For each={api().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"
class="w-[calc(var(--preference-width)-(0.75rem*2))]"
>
<DatePickerContext>
{(api) => (
<>
<DatePickerViewControl>
<DatePickerViewTrigger>
<DatePickerRangeText />
</DatePickerViewTrigger>
</DatePickerViewControl>
<DatePickerTable>
<DatePickerTableBody>
<For
each={api().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"
class="w-[calc(var(--preference-width)-(0.75rem*2))]"
>
<DatePickerContext>
{(api) => (
<>
<DatePickerViewControl>
<DatePickerViewTrigger>
<DatePickerRangeText />
</DatePickerViewTrigger>
</DatePickerViewControl>
<DatePickerTable>
<DatePickerTableBody>
<For
each={api().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>
</div>
</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/default/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"
/>
<title>Bold</title>
</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"
/>
<title>Italic</title>
</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"
/>
<title>Strikethrough</title>
</svg>
</ToggleGroupItem>
</ToggleGroup>
);
};
export default ToggleGroupDemo;
import {
ToggleGroup,
ToggleGroupItem,
} from "@repo/tailwindcss/solid/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"
/>
<title>Bold</title>
</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"
/>
<title>Italic</title>
</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"
/>
<title>Strikethrough</title>
</svg>
</ToggleGroupItem>
</ToggleGroup>
);
};
export default ToggleGroupDemo;
Sonner
import { Button } from "@repo/tailwindcss/default/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;
import { Button } from "@repo/tailwindcss/solid/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.
import { Button } from "@repo/tailwindcss/default/button";
import {
Drawer,
DrawerClose,
DrawerContent,
DrawerDescription,
DrawerFooter,
DrawerHeader,
DrawerLabel,
DrawerTrigger,
} from "@repo/tailwindcss/default/drawer";
import { createSignal } from "solid-js";
const DrawerDemo = () => {
const [goal, setGoal] = createSignal(350);
const onClick = (adjustment: number) => {
setGoal(Math.max(200, Math.min(400, goal() + adjustment)));
};
return (
<Drawer>
<DrawerTrigger as={Button} variant="outline">
Open Drawer
</DrawerTrigger>
<DrawerContent>
<div class="mx-auto w-full max-w-sm">
<DrawerHeader>
<DrawerLabel>Move Goal</DrawerLabel>
<DrawerDescription>Set your daily activity goal.</DrawerDescription>
</DrawerHeader>
<div class="p-4 pb-0">
<div class="flex items-center justify-center space-x-2">
<Button
variant="outline"
size="icon"
class="h-8 w-8 shrink-0 rounded-full"
onClick={() => onClick(-10)}
disabled={goal() <= 200}
>
<svg
class="h-4 w-4"
stroke-width="1.5"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6 12H18"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
<span class="sr-only">Decrease</span>
</Button>
<div class="flex-1 text-center">
<div class="text-7xl font-bold tracking-tighter">{goal()}</div>
<div class="text-[0.70rem] uppercase text-muted-foreground">
Calories/day
</div>
</div>
<Button
variant="outline"
size="icon"
class="h-8 w-8 shrink-0 rounded-full"
onClick={() => onClick(10)}
disabled={goal() >= 400}
>
<svg
class="h-4 w-4"
stroke-width="1.5"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6 12H12M18 12H12M12 12V6M12 12V18"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
<span class="sr-only">Increase</span>
</Button>
</div>
</div>
<DrawerFooter>
<Button>Submit</Button>
<DrawerClose as={Button} variant="outline">
Cancel
</DrawerClose>
</DrawerFooter>
</div>
</DrawerContent>
</Drawer>
);
};
export default DrawerDemo;
import { Button } from "@repo/tailwindcss/solid/button";
import {
Drawer,
DrawerClose,
DrawerContent,
DrawerDescription,
DrawerFooter,
DrawerHeader,
DrawerLabel,
DrawerTrigger,
} from "@repo/tailwindcss/solid/drawer";
import { createSignal } from "solid-js";
const DrawerDemo = () => {
const [goal, setGoal] = createSignal(350);
const onClick = (adjustment: number) => {
setGoal(Math.max(200, Math.min(400, goal() + adjustment)));
};
return (
<Drawer>
<DrawerTrigger as={Button} variant="outline">
Open Drawer
</DrawerTrigger>
<DrawerContent>
<div class="mx-auto w-full max-w-sm">
<DrawerHeader>
<DrawerLabel>Move Goal</DrawerLabel>
<DrawerDescription>Set your daily activity goal.</DrawerDescription>
</DrawerHeader>
<div class="p-4 pb-0">
<div class="flex items-center justify-center space-x-2">
<Button
variant="outline"
size="icon"
class="h-8 w-8 shrink-0 rounded-full"
onClick={() => onClick(-10)}
disabled={goal() <= 200}
>
<svg
class="h-4 w-4"
stroke-width="1.5"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6 12H18"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
<span class="sr-only">Decrease</span>
</Button>
<div class="flex-1 text-center">
<div class="text-7xl font-bold tracking-tighter">{goal()}</div>
<div class="text-[0.70rem] uppercase text-muted-foreground">
Calories/day
</div>
</div>
<Button
variant="outline"
size="icon"
class="h-8 w-8 shrink-0 rounded-full"
onClick={() => onClick(10)}
disabled={goal() >= 400}
>
<svg
class="h-4 w-4"
stroke-width="1.5"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6 12H12M18 12H12M12 12V6M12 12V18"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
<span class="sr-only">Increase</span>
</Button>
</div>
</div>
<DrawerFooter>
<Button>Submit</Button>
<DrawerClose as={Button} variant="outline">
Cancel
</DrawerClose>
</DrawerFooter>
</div>
</DrawerContent>
</Drawer>
);
};
export default DrawerDemo;
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,
DatePickerInput,
DatePickerRangeText,
DatePickerTable,
DatePickerTableBody,
DatePickerTableCell,
DatePickerTableCellTrigger,
DatePickerTableHead,
DatePickerTableHeader,
DatePickerTableRow,
DatePickerView,
DatePickerViewControl,
DatePickerViewTrigger,
} from "@repo/tailwindcss/default/date-picker";
import { Index } from "solid-js";
import { Portal } from "solid-js/web";
const DatePickerDemo = () => {
return (
<DatePicker>
<DatePickerInput placeholder="Pick a date" />
<Portal>
<DatePickerContent>
<DatePickerView view="day">
<DatePickerContext>
{(api) => (
<>
<DatePickerViewControl>
<DatePickerViewTrigger>
<DatePickerRangeText />
</DatePickerViewTrigger>
</DatePickerViewControl>
<DatePickerTable>
<DatePickerTableHead>
<DatePickerTableRow>
<Index each={api().weekDays}>
{(weekDay) => (
<DatePickerTableHeader>
{weekDay().short}
</DatePickerTableHeader>
)}
</Index>
</DatePickerTableRow>
</DatePickerTableHead>
<DatePickerTableBody>
<Index each={api().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"
class="w-[calc(var(--reference-width)-(0.75rem*2))]"
>
<DatePickerContext>
{(api) => (
<>
<DatePickerViewControl>
<DatePickerViewTrigger>
<DatePickerRangeText />
</DatePickerViewTrigger>
</DatePickerViewControl>
<DatePickerTable>
<DatePickerTableBody>
<Index
each={api().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"
class="w-[calc(var(--reference-width)-(0.75rem*2))]"
>
<DatePickerContext>
{(api) => (
<>
<DatePickerViewControl>
<DatePickerViewTrigger>
<DatePickerRangeText />
</DatePickerViewTrigger>
</DatePickerViewControl>
<DatePickerTable>
<DatePickerTableBody>
<Index
each={api().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>
</Portal>
</DatePicker>
);
};
export default DatePickerDemo;
import {
DatePicker,
DatePickerContent,
DatePickerContext,
DatePickerInput,
DatePickerRangeText,
DatePickerTable,
DatePickerTableBody,
DatePickerTableCell,
DatePickerTableCellTrigger,
DatePickerTableHead,
DatePickerTableHeader,
DatePickerTableRow,
DatePickerView,
DatePickerViewControl,
DatePickerViewTrigger,
} from "@repo/tailwindcss/solid/date-picker";
import { Index } from "solid-js";
import { Portal } from "solid-js/web";
const DatePickerDemo = () => {
return (
<DatePicker>
<DatePickerInput placeholder="Pick a date" />
<Portal>
<DatePickerContent>
<DatePickerView view="day">
<DatePickerContext>
{(api) => (
<>
<DatePickerViewControl>
<DatePickerViewTrigger>
<DatePickerRangeText />
</DatePickerViewTrigger>
</DatePickerViewControl>
<DatePickerTable>
<DatePickerTableHead>
<DatePickerTableRow>
<Index each={api().weekDays}>
{(weekDay) => (
<DatePickerTableHeader>
{weekDay().short}
</DatePickerTableHeader>
)}
</Index>
</DatePickerTableRow>
</DatePickerTableHead>
<DatePickerTableBody>
<Index each={api().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"
class="w-[calc(var(--reference-width)-(0.75rem*2))]"
>
<DatePickerContext>
{(api) => (
<>
<DatePickerViewControl>
<DatePickerViewTrigger>
<DatePickerRangeText />
</DatePickerViewTrigger>
</DatePickerViewControl>
<DatePickerTable>
<DatePickerTableBody>
<Index
each={api().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"
class="w-[calc(var(--reference-width)-(0.75rem*2))]"
>
<DatePickerContext>
{(api) => (
<>
<DatePickerViewControl>
<DatePickerViewTrigger>
<DatePickerRangeText />
</DatePickerViewTrigger>
</DatePickerViewControl>
<DatePickerTable>
<DatePickerTableBody>
<Index
each={api().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>
</Portal>
</DatePicker>
);
};
export default DatePickerDemo;
Command
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
CommandShortcut,
} from "@repo/tailwindcss/default/command";
import { type Accessor, For, type JSXElement, Show } from "solid-js";
type Option = {
icon: JSXElement;
label: string;
disabled: boolean;
shortcut?: Accessor<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"
/>
<title>Calendar</title>
</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>
<title>Emoji</title>
</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>
<title>Launch</title>
</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"
/>
<title>Profile</title>
</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>
<title>Mail</title>
</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>
<title>Setting</title>
</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>
{/* @ts-expect-error */}
<Show when={item.shortcut}>{item.shortcut()}</Show>
</CommandItem>
)}
</For>
</CommandGroup>
)}
</For>
</CommandList>
</Command>
);
};
export default CommandDemo;
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
CommandShortcut,
} from "@repo/tailwindcss/solid/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/default/card";
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNext,
CarouselPrevious,
} from "@repo/tailwindcss/default/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;
import { Card, CardContent } from "@repo/tailwindcss/solid/card";
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNext,
CarouselPrevious,
} from "@repo/tailwindcss/solid/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/default/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;
import {
Pagination,
PaginationEllipsis,
PaginationItem,
PaginationItems,
PaginationNext,
PaginationPrevious,
} from "@repo/tailwindcss/solid/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.