1import { Button } from "~/components/ui/button";2import {3 Sheet,4 SheetClose,5 SheetContent,6 SheetDescription,7 SheetFooter,8 SheetHeader,9 SheetTitle,10 SheetTrigger,11} from "~/components/ui/sheet";12import {13 TextField,14 TextFieldInput,15 TextFieldLabel,16} from "~/components/ui/text-field";17
18export default function SheetDemo() {19 return (20 <Sheet>21 <SheetTrigger as={Button<"button">}>Open</SheetTrigger>22 <SheetContent>23 <SheetHeader>24 <SheetTitle>Edit profile</SheetTitle>25 <SheetDescription>26 Make changes to your profile here. Click save when you're done.27 </SheetDescription>28 </SheetHeader>29 <div class="mt-4 grid flex-1 auto-rows-min gap-6">30 <TextField>31 <TextFieldLabel>Name</TextFieldLabel>32 <TextFieldInput id="sheet-demo-name" />33 </TextField>34 <TextField>35 <TextFieldLabel>Email</TextFieldLabel>36 <TextFieldInput id="sheet-demo-email" type="email" />37 </TextField>38 </div>39 <SheetFooter class="grid gap-2">40 <Button type="submit">Save changes</Button>41 <SheetClose as={Button<"button">} variant="neutral">42 Close43 </SheetClose>44 </SheetFooter>45 </SheetContent>46 </Sheet>47 );48}
npx shadcn@latest add https://solid-ui-neobrutalism.vercel.app/r/sheet.json
yarn shadcn@latest add https://solid-ui-neobrutalism.vercel.app/r/sheet.json
pnpm dlx shadcn@latest add https://solid-ui-neobrutalism.vercel.app/r/sheet.json
bunx --bun shadcn@latest add https://solid-ui-neobrutalism.vercel.app/r/sheet.json
Install the following dependencies
npm install @kobalte/core
yarn add @kobalte/core
pnpm add @kobalte/core
bun add @kobalte/core
Copy and paste the following code into your project
1import type { PolymorphicProps } from "@kobalte/core/polymorphic";2import type { VariantProps } from "class-variance-authority";3import type { Component, ComponentProps, JSX, ValidComponent } from "solid-js";4
5import { splitProps } from "solid-js";6import * as SheetPrimitive from "@kobalte/core/dialog";7import { cva } from "class-variance-authority";8import XIcon from "lucide-solid/icons/x";9
10import { cn } from "~/lib/utils";11
12const Sheet = (props: SheetPrimitive.DialogRootProps) => {13 return <SheetPrimitive.Root data-slot="sheet" {...props} />;14};15
16const SheetTrigger = <T extends ValidComponent = "button">(17 props: PolymorphicProps<T, SheetPrimitive.DialogTriggerProps<T>>,18) => {19 return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />;20};21
22const SheetClose = <T extends ValidComponent = "button">(23 props: PolymorphicProps<T, SheetPrimitive.DialogCloseButtonProps<T>>,24) => {25 return <SheetPrimitive.CloseButton data-slot="sheet-close" {...props} />;26};27
28const portalVariants = cva("fixed inset-0 z-50 flex", {29 variants: {30 position: {31 top: "items-start",32 bottom: "items-end",33 left: "justify-start",34 right: "justify-end",35 },36 },37 defaultVariants: { position: "right" },38});39
40type PortalProps = SheetPrimitive.DialogPortalProps &41 VariantProps<typeof portalVariants>;42
43const SheetPortal: Component<PortalProps> = (props) => {44 const [local, others] = splitProps(props, ["position", "children"]);45 return (46 <SheetPrimitive.Portal data-slot="sheet-portal" {...others}>47 <div class={portalVariants({ position: local.position })}>48 {local.children}49 </div>50 </SheetPrimitive.Portal>51 );52};53
54type DialogOverlayProps<T extends ValidComponent = "div"> =55 SheetPrimitive.DialogOverlayProps<T> & {56 class?: string | undefined;57 };58
59const SheetOverlay = <T extends ValidComponent = "div">(60 props: PolymorphicProps<T, DialogOverlayProps<T>>,61) => {62 const [local, others] = splitProps(props as DialogOverlayProps, ["class"]);63 return (64 <SheetPrimitive.Overlay65 data-slot="sheet-overlay"66 class={cn(67 "fixed inset-0 z-50 bg-overlay ui-expanded:animate-in ui-expanded:fade-in-0 ui-closed:animate-out ui-closed:fade-out-0",68 local.class,69 )}70 {...others}71 />72 );73};74
75const sheetVariants = cva(76 "fixed z-50 gap-4 bg-background p-6 transition-all ease-in-out ui-expanded:animate-in ui-expanded:duration-500 ui-closed:animate-out ui-closed:duration-300",77 {78 variants: {79 position: {80 top: "inset-x-0 top-0 border-b ui-expanded:slide-in-from-top ui-closed:slide-out-to-top",81 bottom:82 "inset-x-0 bottom-0 border-t ui-expanded:slide-in-from-bottom ui-closed:slide-out-to-bottom",83 left: "inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm ui-expanded:slide-in-from-left ui-closed:slide-out-to-left",84 right:85 "inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm ui-expanded:slide-in-from-right ui-closed:slide-out-to-right",86 },87 },88 defaultVariants: {89 position: "right",90 },91 },92);93
94type DialogContentProps<T extends ValidComponent = "div"> =95 SheetPrimitive.DialogContentProps<T> &96 VariantProps<typeof sheetVariants> & {97 class?: string | undefined;98 children?: JSX.Element;99 };100
101const SheetContent = <T extends ValidComponent = "div">(102 props: PolymorphicProps<T, DialogContentProps<T>>,103) => {104 const [local, others] = splitProps(props as DialogContentProps, [105 "position",106 "class",107 "children",108 ]);109 return (110 <SheetPortal position={local.position}>111 <SheetOverlay />112 <SheetPrimitive.Content113 data-slot="sheet-content"114 class={cn(115 sheetVariants({ position: local.position }),116 local.class,117 "flex max-h-screen flex-col overflow-y-auto",118 )}119 {...others}120 >121 {local.children}122 <SheetPrimitive.CloseButton123 data-slot="sheet-close-button"124 class="absolute top-4 right-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:outline-none disabled:pointer-events-none ui-expanded:bg-primary"125 >126 <XIcon class="size-4" />127 <span class="sr-only">Close</span>128 </SheetPrimitive.CloseButton>129 </SheetPrimitive.Content>130 </SheetPortal>131 );132};133
134const SheetHeader: Component<ComponentProps<"div">> = (props) => {135 const [local, others] = splitProps(props, ["class"]);136 return (137 <div138 data-slot="sheet-header"139 class={cn(140 "flex flex-col space-y-2 text-center sm:text-left",141 local.class,142 )}143 {...others}144 />145 );146};147
148const SheetFooter: Component<ComponentProps<"div">> = (props) => {149 const [local, others] = splitProps(props, ["class"]);150 return (151 <div152 data-slot="sheet-footer"153 class={cn("mt-auto flex flex-col", local.class)}154 {...others}155 />156 );157};158
159type DialogTitleProps<T extends ValidComponent = "h2"> =160 SheetPrimitive.DialogTitleProps<T> & {161 class?: string | undefined;162 };163
164const SheetTitle = <T extends ValidComponent = "h2">(165 props: PolymorphicProps<T, DialogTitleProps<T>>,166) => {167 const [local, others] = splitProps(props as DialogTitleProps, ["class"]);168 return (169 <SheetPrimitive.Title170 data-slot="sheet-title"171 class={cn("text-lg font-semibold text-foreground", local.class)}172 {...others}173 />174 );175};176
177type DialogDescriptionProps<T extends ValidComponent = "p"> =178 SheetPrimitive.DialogDescriptionProps<T> & { class?: string | undefined };179
180const SheetDescription = <T extends ValidComponent = "p">(181 props: PolymorphicProps<T, DialogDescriptionProps<T>>,182) => {183 const [local, others] = splitProps(props as DialogDescriptionProps, [184 "class",185 ]);186 return (187 <SheetPrimitive.Description188 data-slot="sheet-description"189 class={cn("text-sm text-muted-foreground", local.class)}190 {...others}191 />192 );193};194
195export {196 Sheet,197 SheetTrigger,198 SheetClose,199 SheetContent,200 SheetHeader,201 SheetFooter,202 SheetTitle,203 SheetDescription,204};
Update the import paths to match your project setup.
1import {2 Sheet,3 SheetClose,4 SheetContent,5 SheetDescription,6 SheetFooter,7 SheetHeader,8 SheetTitle,9 SheetTrigger,10} from "~/components/ui/sheet";
1<Sheet>2 <SheetTrigger>Open</SheetTrigger>3 <SheetContent>4 <SheetHeader>5 <SheetTitle>Are you absolutely sure?</SheetTitle>6 <SheetDescription>7 This action cannot be undone. This will permanently delete your account8 and remove your data from our servers.9 </SheetDescription>10 </SheetHeader>11 </SheetContent>12</Sheet>
1import { Button } from "~/components/ui/button";2import {3 Sheet,4 SheetContent,5 SheetDescription,6 SheetHeader,7 SheetTitle,8 SheetTrigger,9} from "~/components/ui/sheet";10
11export default function SheetSide() {12 return (13 <div class="grid grid-cols-2 gap-4">14 <SheetLeft />15 <SheetTop />16 <SheetRight />17 <SheetBottom />18 </div>19 );20}21
22function SheetLeft() {23 return (24 <Sheet>25 <SheetTrigger as={Button<"button">}>Left</SheetTrigger>26 <SheetContent position="left">27 <SheetHeader>28 <SheetTitle>Are you absolutely sure?</SheetTitle>29 <SheetDescription>30 This action cannot be undone. This will permanently delete your31 account and remove your data from our servers.32 </SheetDescription>33 </SheetHeader>34 </SheetContent>35 </Sheet>36 );37}38
39function SheetTop() {40 return (41 <Sheet>42 <SheetTrigger as={Button<"button">}>Top</SheetTrigger>43 <SheetContent position="top">44 <SheetHeader>45 <SheetTitle>Are you absolutely sure?</SheetTitle>46 <SheetDescription>47 This action cannot be undone. This will permanently delete your48 account and remove your data from our servers.49 </SheetDescription>50 </SheetHeader>51 </SheetContent>52 </Sheet>53 );54}55
56function SheetRight() {57 return (58 <Sheet>59 <SheetTrigger as={Button<"button">}>Right</SheetTrigger>60 <SheetContent position="right">61 <SheetHeader>62 <SheetTitle>Are you absolutely sure?</SheetTitle>63 <SheetDescription>64 This action cannot be undone. This will permanently delete your65 account and remove your data from our servers.66 </SheetDescription>67 </SheetHeader>68 </SheetContent>69 </Sheet>70 );71}72
73function SheetBottom() {74 return (75 <Sheet>76 <SheetTrigger as={Button<"button">}>Bottom</SheetTrigger>77 <SheetContent position="bottom">78 <SheetHeader>79 <SheetTitle>Are you absolutely sure?</SheetTitle>80 <SheetDescription>81 This action cannot be undone. This will permanently delete your82 account and remove your data from our servers.83 </SheetDescription>84 </SheetHeader>85 </SheetContent>86 </Sheet>87 );88}