Zaidan

Command Palette

Search for a command to run...

GitHub69

Sheet

Extends the Dialog component to display content that complements the main content of the screen.

Installation

CLI

Manual

Install the following dependencies:

Copy and paste the following code into your project.

import * as SheetPrimitive from "@kobalte/core/dialog";
import type { PolymorphicProps } from "@kobalte/core/polymorphic";
import { X } from "lucide-solid";
import type { Component, ComponentProps, ValidComponent } from "solid-js";
import { mergeProps, Show, splitProps } from "solid-js";
import { cn } from "~/lib/utils";
import { Button } from "./button";
const Sheet: Component<SheetPrimitive.DialogRootProps> = (props) => {
return <SheetPrimitive.Root data-slot="sheet" {...props} />;
};
type SheetTriggerProps<T extends ValidComponent = "button"> = PolymorphicProps<
T,
SheetPrimitive.DialogTriggerProps<T>
>;
const SheetTrigger = <T extends ValidComponent = "button">(props: SheetTriggerProps<T>) => {
return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />;
};
type SheetCloseProps<T extends ValidComponent = "button"> = PolymorphicProps<
T,
SheetPrimitive.DialogCloseButtonProps<T>
>;
const SheetClose = <T extends ValidComponent = "button">(props: SheetCloseProps<T>) => {
return <SheetPrimitive.CloseButton data-slot="sheet-close" {...props} />;
};
const SheetPortal = (props: SheetPrimitive.DialogPortalProps) => {
return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} />;
};
type SheetOverlayProps<T extends ValidComponent = "div"> = PolymorphicProps<
T,
SheetPrimitive.DialogOverlayProps<T>
> &
Pick<ComponentProps<T>, "class">;
const SheetOverlay = <T extends ValidComponent = "div">(props: SheetOverlayProps<T>) => {
const [local, others] = splitProps(props as SheetOverlayProps, ["class"]);
return (
<SheetPrimitive.Overlay
data-slot="sheet-overlay"
class={cn("fixed inset-0 z-50 z-sheet-overlay", local.class)}
{...others}
/>
);
};
type SheetContentProps<T extends ValidComponent = "div"> = PolymorphicProps<
T,
SheetPrimitive.DialogContentProps<T>
> &
Pick<ComponentProps<T>, "class" | "children"> & {
side?: "top" | "right" | "bottom" | "left";
showCloseButton?: boolean;
};
const SheetContent = <T extends ValidComponent = "div">(props: SheetContentProps<T>) => {
const mergedProps = mergeProps(
{ side: "right", showCloseButton: true } as SheetContentProps,
props,
);
const [local, others] = splitProps(mergedProps, ["class", "children", "side", "showCloseButton"]);
return (
<SheetPortal>
<SheetOverlay />
<SheetPrimitive.Content
data-slot="sheet-content"
data-side={local.side}
class={cn("z-sheet-content", local.class)}
{...others}
>
{local.children}
<Show when={local.showCloseButton}>
<SheetPrimitive.CloseButton
as={Button}
variant="ghost"
size="icon-sm"
data-slot="sheet-close"
class="z-sheet-close"
>
<X />
<span class="sr-only">Close</span>
</SheetPrimitive.CloseButton>
</Show>
</SheetPrimitive.Content>
</SheetPortal>
);
};
type SheetHeaderProps = ComponentProps<"div">;
const SheetHeader = (props: SheetHeaderProps) => {
const [local, others] = splitProps(props, ["class"]);
return (
<div
data-slot="sheet-header"
class={cn("z-sheet-header flex flex-col", local.class)}
{...others}
/>
);
};
type SheetFooterProps = ComponentProps<"div">;
const SheetFooter = (props: SheetFooterProps) => {
const [local, others] = splitProps(props, ["class"]);
return (
<div
data-slot="sheet-footer"
class={cn("z-sheet-footer mt-auto flex flex-col", local.class)}
{...others}
/>
);
};
type SheetTitleProps<T extends ValidComponent = "h2"> = PolymorphicProps<
T,
SheetPrimitive.DialogTitleProps<T>
> &
Pick<ComponentProps<T>, "class">;
const SheetTitle = <T extends ValidComponent = "h2">(props: SheetTitleProps<T>) => {
const [local, others] = splitProps(props as SheetTitleProps, ["class"]);
return (
<SheetPrimitive.Title
data-slot="sheet-title"
class={cn("z-sheet-title", local.class)}
{...others}
/>
);
};
type SheetDescriptionProps<T extends ValidComponent = "p"> = PolymorphicProps<
T,
SheetPrimitive.DialogDescriptionProps<T>
> &
Pick<ComponentProps<T>, "class">;
const SheetDescription = <T extends ValidComponent = "p">(props: SheetDescriptionProps<T>) => {
const [local, others] = splitProps(props as SheetDescriptionProps, ["class"]);
return (
<SheetPrimitive.Description
data-slot="sheet-description"
class={cn("z-sheet-description", local.class)}
{...others}
/>
);
};
export {
Sheet,
SheetTrigger,
SheetClose,
SheetContent,
SheetHeader,
SheetFooter,
SheetTitle,
SheetDescription,
};

Examples

Here are the source code of all the examples from the preview page:

With Form

import { Button } from "~/components/ui/button";
import { Input } from "~/components/ui/input";
import { Label } from "~/components/ui/label";
import {
Sheet,
SheetClose,
SheetContent,
SheetDescription,
SheetFooter,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "~/components/ui/sheet";
function SheetWithForm() {
return (
<Example title="With Form">
<Sheet>
<SheetTrigger as={Button} variant="outline">
Open
</SheetTrigger>
<SheetContent>
<SheetHeader>
<SheetTitle>Edit profile</SheetTitle>
<SheetDescription>
Make changes to your profile here. Click save when you&apos;re done.
</SheetDescription>
</SheetHeader>
<div class="px-4">
<div class="flex flex-col gap-4">
<div class="flex flex-col gap-2">
<Label for="sheet-demo-name">Name</Label>
<Input id="sheet-demo-name" value="Pedro Duarte" />
</div>
<div class="flex flex-col gap-2">
<Label for="sheet-demo-username">Username</Label>
<Input id="sheet-demo-username" value="@peduarte" />
</div>
</div>
</div>
<SheetFooter>
<Button type="submit">Save changes</Button>
<SheetClose as={Button} variant="outline">
Close
</SheetClose>
</SheetFooter>
</SheetContent>
</Sheet>
</Example>
);
}

No Close Button

import { Button } from "~/components/ui/button";
import {
Sheet,
SheetContent,
SheetDescription,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "~/components/ui/sheet";
function SheetNoCloseButton() {
return (
<Example title="No Close Button">
<Sheet>
<SheetTrigger as={Button} variant="outline">
No Close Button
</SheetTrigger>
<SheetContent showCloseButton={false}>
<SheetHeader>
<SheetTitle>No Close Button</SheetTitle>
<SheetDescription>
This sheet doesn&apos;t have a close button in the top-right corner. You can only
close it using the button below.
</SheetDescription>
</SheetHeader>
</SheetContent>
</Sheet>
</Example>
);
}

Sides

Use the side property to <SheetContent /> to indicate the edge of the screen where the component will appear. The values can be top, right, bottom or left.

import { For, Index } from "solid-js";
import { Button } from "~/components/ui/button";
import {
Sheet,
SheetClose,
SheetContent,
SheetDescription,
SheetFooter,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "~/components/ui/sheet";
const SHEET_SIDES = ["top", "right", "bottom", "left"] as const;
function SheetWithSides() {
return (
<Example title="Sides">
<div class="flex flex-wrap gap-2">
<For each={SHEET_SIDES}>
{(side) => (
<Sheet>
<SheetTrigger as={Button} variant="outline" class="capitalize">
{side}
</SheetTrigger>
<SheetContent
side={side}
class="data-[side=bottom]:max-h-[50vh] data-[side=top]:max-h-[50vh]"
>
<SheetHeader>
<SheetTitle>Edit profile</SheetTitle>
<SheetDescription>
Make changes to your profile here. Click save when you&apos;re done.
</SheetDescription>
</SheetHeader>
<div class="no-scrollbar overflow-y-auto px-4">
<Index each={Array.from({ length: 10 })}>
{() => (
<p class="mb-4 style-lyra:mb-2 leading-normal style-lyra:leading-relaxed">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat
non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
)}
</Index>
</div>
<SheetFooter>
<Button type="submit">Save changes</Button>
<SheetClose as={Button} variant="outline">
Cancel
</SheetClose>
</SheetFooter>
</SheetContent>
</Sheet>
)}
</For>
</div>
</Example>
);
}

Size

You can adjust the size of the sheet using CSS classes:

<Sheet>
<SheetTrigger>Open</SheetTrigger>
<SheetContent class="w-[400px] sm:w-[540px]">
<SheetHeader>
<SheetTitle>Are you absolutely sure?</SheetTitle>
<SheetDescription>
This action cannot be undone. This will permanently delete your account
and remove your data from our servers.
</SheetDescription>
</SheetHeader>
</SheetContent>
</Sheet>