Sheet
Displays content on one side of the screen in a modal dialog.
<Sheet>
<SheetTrigger>
<Button variant="outline">Open</Button>
</SheetTrigger>
<SheetContent>
<SheetHeader>
<SheetTitle>Edit profile</SheetTitle>
<SheetDescription>
Make changes to your profile here. Click save when you're done.
</SheetDescription>
</SheetHeader>
<div class="grid gap-4 py-4">
<div class="grid grid-cols-4 items-center gap-4">
<Label htmlFor="name" className="text-right">
Name
</Label>
<Input id="name" value="Pedro Duarte" className="col-span-3" />
</div>
<div class="grid grid-cols-4 items-center gap-4">
<Label htmlFor="username" className="text-right">
Username
</Label>
<Input id="username" value="@peduarte" className="col-span-3" />
</div>
</div>
<SheetFooter>
<SheetClose asChild>
<Button type="submit">Save changes</Button>
</SheetClose>
</SheetFooter>
</SheetContent>
</Sheet>
Installation
uvx --from basic-components components add sheet
pipx run --spec basic-components components add sheet
pip install basic-components && components add sheet
- Copy Sheet components below to your local environment
- Place them in the components/ui/sheet directory in your project
- Configure your jinja environment for JinjaX
- Add the cn() helper function to your global jinja environment
Usage
<Alert>
<TerminalIcon className="h-4 w-4" />
<AlertTitle>Heads up!</AlertTitle>
<AlertDescription>
You can add components to your app using the cli.
</AlertDescription>
</Alert>
Attributes
Component | Prop | Type | Default | Description |
---|---|---|---|---|
SheetContent | side |
String | "right" |
Position of the sheet (top/bottom/left/right). |
Code
{#def
className: str = "",
#}
<div x-data="{ open: false }"
x-init="$watch('open', value => document.body.classList.toggle('overflow-hidden', value))"
class="{{ className }}"
{{ attrs.render() }}
>{{ content }}</div>
{#def
className: str = "",
#}
<button
type="button"
@click="open = false"
class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-white transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-zinc-950 focus:ring-offset-2 dark:ring-offset-zinc-950 dark:focus:ring-zinc-300"
>
<XIcon className="h-4 w-4"/>
<span class="sr-only">Close</span>
{{ content }}
</button>
{#def
side: str = "right",
className: str = "",
#}
{% set layout = {
'top': 'inset-x-0 top-0 border-b slide-in-from-top overflow-x-auto',
'bottom': 'inset-x-0 bottom-0 border-t slide-in-from-bottom overflow-x-auto',
'left': 'inset-y-0 left-0 h-full w-3/4 border-r slide-in-from-left sm:max-w-sm overflow-y-auto',
'right': 'inset-y-0 right-0 h-full w-3/4 border-l slide-in-from-right sm:max-w-sm overflow-y-auto',
}[side] %}
<SheetOverlay/>
<div
x-show="open"
@keydown.escape.window="open = false"
@click.away="open = false"
x-transition:enter="transition ease-in-out duration-300"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition ease-in-out duration-300"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
class="{{ layout }} {{ className }} fixed z-50 gap-4 bg-white p-6 shadow-lg transition ease-in-out dark:bg-zinc-950"
{{ attrs.render() }}
>
{{ content }}
<SheetClose/>
</div>
{#def
className: str = "",
#}
<p class="{{ className }} text-sm text-zinc-500 dark:text-zinc-400">{{ content }}</p>
{#def
className: str = "",
#}
<div class="{{ className }} flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2">
{{ content }}
</div>
{#def
className: str = "",
#}
<div class="{{ className }} flex flex-col space-y-2 text-center sm:text-left">{{ content }}</div>
{#def
className: str = "",
#}
<div
class="{{ className }} fixed inset-0 z-50 bg-black/80 transition-opacity ease-in-out overflow-hidden"
x-show="open"
x-transition:enter="transition-opacity duration-300"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition-opacity duration-300"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
></div>
{#def
className: str = "",
#}
<h2 class="{{ className }} text-lg font-semibold text-zinc-950 dark:text-zinc-50">{{ content }}</h2>
{#def
className: str = "",
#}
<div @click="open = true" class="inline-block {{ className }}">{{ content }}</div>
Examples
Sides
<div class="grid grid-cols-2 gap-2 place-items-center">
{% for side in ["top", "right", "bottom", "left" ] %}
<Sheet :id="{{ side }}">
<SheetTrigger>
<Button variant="outline">{{ side }}</Button>
</SheetTrigger>
<SheetContent :side="{{ side }}">
<SheetHeader>
<SheetTitle>Edit profile</SheetTitle>
<SheetDescription>
Make changes to your profile here. Click save when you're done.
</SheetDescription>
</SheetHeader>
<div class="grid gap-4 py-4">
<div class="grid grid-cols-4 items-center gap-4">
<Label htmlFor="name" className="text-right">
Name
</Label>
<Input id="name" value="Pedro Duarte" className="col-span-3"/>
</div>
<div class="grid grid-cols-4 items-center gap-4">
<Label htmlFor="username" className="text-right">
Username
</Label>
<Input id="username" value="@peduarte" className="col-span-3"/>
</div>
</div>
<SheetFooter>
<SheetClose>
<Button type="submit">Save changes</Button>
</SheetClose>
</SheetFooter>
</SheetContent>
</Sheet>
{% endfor %}
</div>