Sheet
A sliding panel that appears from the side of the screen
Side Positions
Sheets can slide from any edge of the viewport.
1
2<script lang="ts">
3 import { Sheet, SheetPrimitives, Button } from "@kareyes/aether";
4 import { Menu } from "@kareyes/aether/icons";
5
6 const {
7 SheetTrigger,
8 SheetContent,
9 SheetHeader,
10 SheetTitle,
11 SheetDescription,
12 } = SheetPrimitives;
13</script>
14
15<div class="flex flex-wrap gap-4">
16 <!-- Right Side (Default) -->
17 <Sheet>
18 <SheetTrigger>
19 <Button variant="outline">Right (Default)</Button>
20 </SheetTrigger>
21 <SheetContent side="right">
22 <SheetHeader>
23 <SheetTitle>Right Side Sheet</SheetTitle>
24 <SheetDescription>
25 This sheet slides in from the right side of the screen.
26 </SheetDescription>
27 </SheetHeader>
28 <div class="py-4">
29 <p class="text-sm text-muted-foreground">
30 Commonly used for forms, settings, and detail panels.
31 </p>
32 </div>
33 </SheetContent>
34 </Sheet>
35
36 <!-- Left Side -->
37 <Sheet>
38 <SheetTrigger>
39 <Button variant="outline">
40 <Menu class="mr-2 size-4" />
41 Left
42 </Button>
43 </SheetTrigger>
44 <SheetContent side="left">
45 <SheetHeader>
46 <SheetTitle>Left Side Sheet</SheetTitle>
47 <SheetDescription>
48 This sheet slides in from the left side of the screen.
49 </SheetDescription>
50 </SheetHeader>
51 <div class="py-4">
52 <p class="text-sm text-muted-foreground">
53 Perfect for navigation menus and sidebars.
54 </p>
55 </div>
56 </SheetContent>
57 </Sheet>
58
59 <!-- Top Side -->
60 <Sheet>
61 <SheetTrigger>
62 <Button variant="outline">Top</Button>
63 </SheetTrigger>
64 <SheetContent side="top">
65 <SheetHeader>
66 <SheetTitle>Top Side Sheet</SheetTitle>
67 <SheetDescription>
68 This sheet slides down from the top of the screen.
69 </SheetDescription>
70 </SheetHeader>
71 <div class="py-4">
72 <p class="text-sm text-muted-foreground">
73 Great for announcements and banners.
74 </p>
75 </div>
76 </SheetContent>
77 </Sheet>
78
79 <!-- Bottom Side -->
80 <Sheet>
81 <SheetTrigger>
82 <Button variant="outline">Bottom</Button>
83 </SheetTrigger>
84 <SheetContent side="bottom">
85 <SheetHeader>
86 <SheetTitle>Bottom Side Sheet</SheetTitle>
87 <SheetDescription>
88 This sheet slides up from the bottom of the screen.
89 </SheetDescription>
90 </SheetHeader>
91 <div class="py-4">
92 <p class="text-sm text-muted-foreground">
93 Ideal for mobile-style notifications and quick actions.
94 </p>
95 </div>
96 </SheetContent>
97 </Sheet>
98</div>Form Examples
Sheets are perfect for containing forms and input workflows.
Profile Edit
Contact Form
Account Creation
1
2<script lang="ts">
3 import { Sheet, SheetPrimitives, Button, Input, Label, Textarea } from "@kareyes/aether";
4 import { Mail } from "@kareyes/aether/icons";
5
6 const {
7 SheetTrigger,
8 SheetContent,
9 SheetHeader,
10 SheetFooter,
11 SheetTitle,
12 SheetDescription,
13 SheetClose,
14 } = SheetPrimitives;
15</script>
16
17<!-- Profile Edit Form -->
18<div class="space-y-2">
19 <h3 class="text-sm font-medium">Profile Edit</h3>
20 <Sheet>
21 <SheetTrigger>
22 <Button variant="outline">Edit Profile</Button>
23 </SheetTrigger>
24 <SheetContent>
25 <SheetHeader>
26 <SheetTitle>Edit Profile</SheetTitle>
27 <SheetDescription>
28 Make changes to your profile here. Click save when you're done.
29 </SheetDescription>
30 </SheetHeader>
31 <div class="grid gap-4 py-4">
32 <div class="grid grid-cols-4 items-center gap-4">
33 <Label for="name" class="text-end">Name</Label>
34 <Input id="name" value="Pedro Duarte" class="col-span-3" />
35 </div>
36 <div class="grid grid-cols-4 items-center gap-4">
37 <Label for="username" class="text-end">Username</Label>
38 <Input id="username" value="@peduarte" class="col-span-3" />
39 </div>
40 </div>
41 <SheetFooter>
42 <SheetClose>
43 <Button variant="outline">Cancel</Button>
44 </SheetClose>
45 <Button type="submit">Save changes</Button>
46 </SheetFooter>
47 </SheetContent>
48 </Sheet>
49</div>
50
51<!-- Contact Form -->
52<div class="space-y-2">
53 <h3 class="text-sm font-medium">Contact Form</h3>
54 <Sheet>
55 <SheetTrigger>
56 <Button variant="outline">
57 <Mail class="mr-2 size-4" />
58 Contact Us
59 </Button>
60 </SheetTrigger>
61 <SheetContent>
62 <SheetHeader>
63 <SheetTitle>Contact Us</SheetTitle>
64 <SheetDescription>
65 Send us a message and we'll get back to you soon.
66 </SheetDescription>
67 </SheetHeader>
68 <div class="grid gap-4 py-4">
69 <div class="grid gap-2">
70 <Label for="contact-name">Name</Label>
71 <Input id="contact-name" placeholder="Your name" />
72 </div>
73 <div class="grid gap-2">
74 <Label for="message">Message</Label>
75 <Textarea id="message" placeholder="Type your message here..." rows={5} />
76 </div>
77 </div>
78 <SheetFooter>
79 <SheetClose>
80 <Button variant="outline">Cancel</Button>
81 </SheetClose>
82 <Button>Send Message</Button>
83 </SheetFooter>
84 </SheetContent>
85 </Sheet>
86</div>
87
88<!-- Create Account -->
89<div class="space-y-2">
90 <h3 class="text-sm font-medium">Account Creation</h3>
91 <Sheet>
92 <SheetTrigger>
93 <Button>Create Account</Button>
94 </SheetTrigger>
95 <SheetContent>
96 <SheetHeader>
97 <SheetTitle>Create Account</SheetTitle>
98 <SheetDescription>
99 Fill in your details to create a new account.
100 </SheetDescription>
101 </SheetHeader>
102 <div class="grid gap-4 py-4">
103 <div class="grid gap-2">
104 <Label for="new-name">Full Name</Label>
105 <Input id="new-name" placeholder="John Doe" />
106 </div>
107 <div class="grid gap-2">
108 <Label for="new-email">Email</Label>
109 <Input id="new-email" type="email" placeholder="you@example.com" />
110 </div>
111 <div class="grid gap-2">
112 <Label for="new-password">Password</Label>
113 <Input id="new-password" type="password" />
114 </div>
115 </div>
116 <SheetFooter>
117 <SheetClose>
118 <Button variant="outline">Cancel</Button>
119 </SheetClose>
120 <Button type="submit">Create Account</Button>
121 </SheetFooter>
122 </SheetContent>
123 </Sheet>
124</div>Navigation & Menu
Use sheets for mobile-friendly navigation menus.
1
2<script lang="ts">
3 import { Sheet, SheetPrimitives, Button } from "@kareyes/aether";
4 import { Menu, Home, FileText, Settings, Mail, HelpCircle } from "@kareyes/aether/icons";
5
6 const {
7 SheetTrigger,
8 SheetContent,
9 SheetHeader,
10 SheetTitle,
11 SheetDescription,
12 } = SheetPrimitives;
13</script>
14
15<Sheet>
16 <SheetTrigger>
17 <Button variant="outline">
18 <Menu class="mr-2 size-4" />
19 Open Menu
20 </Button>
21 </SheetTrigger>
22 <SheetContent side="left">
23 <SheetHeader>
24 <SheetTitle>Navigation Menu</SheetTitle>
25 <SheetDescription>
26 Browse different sections of the application.
27 </SheetDescription>
28 </SheetHeader>
29 <nav class="flex flex-col gap-4 py-4">
30 <a href="#home" class="flex items-center gap-2 text-lg font-medium hover:underline">
31 <Home class="size-5" />
32 Home
33 </a>
34 <a href="#about" class="flex items-center gap-2 text-lg font-medium hover:underline">
35 <FileText class="size-5" />
36 About
37 </a>
38 <a href="#services" class="flex items-center gap-2 text-lg font-medium hover:underline">
39 <Settings class="size-5" />
40 Services
41 </a>
42 <a href="#contact" class="flex items-center gap-2 text-lg font-medium hover:underline">
43 <Mail class="size-5" />
44 Contact
45 </a>
46 <a href="#help" class="flex items-center gap-2 text-lg font-medium hover:underline">
47 <HelpCircle class="size-5" />
48 Help
49 </a>
50 </nav>
51 </SheetContent>
52</Sheet>Settings Panel
Complex settings interfaces with tabs and sections.
1
2<script lang="ts">
3 import { Sheet, SheetPrimitives, Tabs, TabsPrimitives, Button, Input, Label } from "@kareyes/aether";
4 import { Settings } from "@kareyes/aether/icons";
5
6 const {
7 SheetTrigger,
8 SheetContent,
9 SheetHeader,
10 SheetFooter,
11 SheetTitle,
12 SheetDescription,
13 SheetClose,
14 } = SheetPrimitives;
15
16 const { TabsList, TabsTrigger, TabsContent } = TabsPrimitives;
17</script>
18
19<Sheet>
20 <SheetTrigger>
21 <Button variant="outline">
22 <Settings class="mr-2 size-4" />
23 Settings
24 </Button>
25 </SheetTrigger>
26 <SheetContent>
27 <SheetHeader>
28 <SheetTitle>Settings</SheetTitle>
29 <SheetDescription>
30 Manage your account settings and preferences.
31 </SheetDescription>
32 </SheetHeader>
33 <Tabs value="account" class="py-4">
34 <TabsList class="grid w-full grid-cols-2">
35 <TabsTrigger value="account">Account</TabsTrigger>
36 <TabsTrigger value="security">Security</TabsTrigger>
37 </TabsList>
38 <TabsContent value="account" class="space-y-4">
39 <div class="space-y-2">
40 <Label for="display-name">Display Name</Label>
41 <Input id="display-name" placeholder="Your name" />
42 </div>
43 <div class="space-y-2">
44 <Label for="language">Language</Label>
45 <select id="language" class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm">
46 <option>English</option>
47 <option>Spanish</option>
48 <option>French</option>
49 </select>
50 </div>
51 </TabsContent>
52 <TabsContent value="security" class="space-y-4">
53 <div class="space-y-2">
54 <Label for="current-password">Current Password</Label>
55 <Input id="current-password" type="password" />
56 </div>
57 <div class="space-y-2">
58 <Label for="new-pass">New Password</Label>
59 <Input id="new-pass" type="password" />
60 </div>
61 </TabsContent>
62 </Tabs>
63 <SheetFooter>
64 <SheetClose>
65 <Button variant="outline">Cancel</Button>
66 </SheetClose>
67 <Button>Save Changes</Button>
68 </SheetFooter>
69 </SheetContent>
70</Sheet>Notifications
Display notifications and alerts from different positions.
Announcements (Top)
Recent Activity (Bottom)
1
2<script lang="ts">
3 import { Sheet, SheetPrimitives, Button } from "@kareyes/aether";
4 import { Bell } from "@kareyes/aether/icons";
5
6 const {
7 SheetTrigger,
8 SheetContent,
9 SheetHeader,
10 SheetTitle,
11 SheetDescription,
12 } = SheetPrimitives;
13</script>
14
15<!-- Top Notifications -->
16<div class="space-y-2">
17 <h3 class="text-sm font-medium">Announcements (Top)</h3>
18 <Sheet>
19 <SheetTrigger>
20 <Button variant="outline">
21 <Bell class="mr-2 size-4" />
22 Announcements
23 </Button>
24 </SheetTrigger>
25 <SheetContent side="top">
26 <SheetHeader>
27 <SheetTitle>Important Announcements</SheetTitle>
28 <SheetDescription>
29 Read the latest updates and announcements.
30 </SheetDescription>
31 </SheetHeader>
32 <div class="space-y-4 py-4">
33 <div class="rounded-lg border p-4">
34 <h4 class="font-semibold">System Maintenance</h4>
35 <p class="text-sm text-muted-foreground">
36 Scheduled maintenance on Sunday, 2AM - 4AM EST.
37 </p>
38 </div>
39 <div class="rounded-lg border p-4">
40 <h4 class="font-semibold">New Features Released</h4>
41 <p class="text-sm text-muted-foreground">
42 Check out our latest features in the dashboard.
43 </p>
44 </div>
45 </div>
46 </SheetContent>
47 </Sheet>
48</div>
49
50<!-- Bottom Notifications -->
51<div class="space-y-2">
52 <h3 class="text-sm font-medium">Recent Activity (Bottom)</h3>
53 <Sheet>
54 <SheetTrigger>
55 <Button variant="outline">
56 <Bell class="mr-2 size-4" />
57 Recent Activity
58 </Button>
59 </SheetTrigger>
60 <SheetContent side="bottom">
61 <SheetHeader>
62 <SheetTitle>Recent Notifications</SheetTitle>
63 <SheetDescription>
64 You have 3 unread notifications.
65 </SheetDescription>
66 </SheetHeader>
67 <div class="space-y-4 py-4">
68 <div class="flex items-start gap-4 border-b pb-4">
69 <div class="flex-1">
70 <p class="font-medium">New message received</p>
71 <p class="text-sm text-muted-foreground">2 minutes ago</p>
72 </div>
73 </div>
74 <div class="flex items-start gap-4">
75 <div class="flex-1">
76 <p class="font-medium">Task completed</p>
77 <p class="text-sm text-muted-foreground">3 hours ago</p>
78 </div>
79 </div>
80 </div>
81 </SheetContent>
82 </Sheet>
83</div>E-commerce Examples
Common patterns for shopping and checkout flows.
Shopping Cart
1
2<script lang="ts">
3 import { Sheet, SheetPrimitives, Button } from "@kareyes/aether";
4 import { ShoppingCart, CreditCard } from "@kareyes/aether/icons";
5
6 const {
7 SheetTrigger,
8 SheetContent,
9 SheetHeader,
10 SheetFooter,
11 SheetTitle,
12 SheetDescription,
13 SheetClose,
14 } = SheetPrimitives;
15</script>
16
17<div class="space-y-2">
18 <h3 class="text-sm font-medium">Shopping Cart</h3>
19 <Sheet>
20 <SheetTrigger>
21 <Button variant="outline">
22 <ShoppingCart class="mr-2 size-4" />
23 Cart (3)
24 </Button>
25 </SheetTrigger>
26 <SheetContent>
27 <SheetHeader>
28 <SheetTitle>Shopping Cart</SheetTitle>
29 <SheetDescription>
30 You have 3 items in your cart.
31 </SheetDescription>
32 </SheetHeader>
33 <div class="space-y-4 py-4">
34 <div class="flex items-center gap-4 border-b pb-4">
35 <div class="size-16 rounded bg-muted"></div>
36 <div class="flex-1">
37 <p class="font-medium">Wireless Headphones</p>
38 <p class="text-sm text-muted-foreground">$79.99</p>
39 </div>
40 <Button variant="ghost" size="sm">Remove</Button>
41 </div>
42 <div class="flex items-center gap-4 border-b pb-4">
43 <div class="size-16 rounded bg-muted"></div>
44 <div class="flex-1">
45 <p class="font-medium">Smart Watch</p>
46 <p class="text-sm text-muted-foreground">$199.99</p>
47 </div>
48 <Button variant="ghost" size="sm">Remove</Button>
49 </div>
50 <div class="flex items-center justify-between pt-4">
51 <span class="font-semibold">Total:</span>
52 <span class="text-xl font-bold">$299.97</span>
53 </div>
54 </div>
55 <SheetFooter class="flex-col gap-2 sm:flex-col">
56 <Button class="w-full">
57 <CreditCard class="mr-2 size-4" />
58 Checkout
59 </Button>
60 <SheetClose>
61 <Button variant="outline" class="w-full">Continue Shopping</Button>
62 </SheetClose>
63 </SheetFooter>
64 </SheetContent>
65 </Sheet>
66</div>User Profile
Display user information and account actions.
1
2<script lang="ts">
3 import { Sheet, SheetPrimitives, Button } from "@kareyes/aether";
4 import { User, Lock, Settings } from "@kareyes/aether/icons";
5
6 const {
7 SheetTrigger,
8 SheetContent,
9 SheetHeader,
10 SheetTitle,
11 SheetDescription,
12 } = SheetPrimitives;
13</script>
14
15<Sheet>
16 <SheetTrigger>
17 <Button variant="ghost" size="icon">
18 <User class="size-4" />
19 </Button>
20 </SheetTrigger>
21 <SheetContent>
22 <SheetHeader>
23 <SheetTitle>User Profile</SheetTitle>
24 <SheetDescription>
25 View and manage your profile information.
26 </SheetDescription>
27 </SheetHeader>
28 <div class="space-y-6 py-4">
29 <div class="flex items-center gap-4">
30 <div class="flex size-16 items-center justify-center rounded-full bg-primary text-primary-foreground">
31 <User class="size-8" />
32 </div>
33 <div>
34 <p class="font-semibold">John Doe</p>
35 <p class="text-sm text-muted-foreground">john.doe@example.com</p>
36 </div>
37 </div>
38 <div class="space-y-2">
39 <h4 class="text-sm font-medium">Account Details</h4>
40 <div class="space-y-1 text-sm">
41 <p><span class="text-muted-foreground">Member since:</span> January 2024</p>
42 <p><span class="text-muted-foreground">Account type:</span> Premium</p>
43 </div>
44 </div>
45 <div class="space-y-2">
46 <Button variant="outline" class="w-full justify-start">
47 <User class="mr-2 size-4" />
48 Edit Profile
49 </Button>
50 <Button variant="outline" class="w-full justify-start">
51 <Lock class="mr-2 size-4" />
52 Change Password
53 </Button>
54 <Button variant="outline" class="w-full justify-start">
55 <Settings class="mr-2 size-4" />
56 Account Settings
57 </Button>
58 </div>
59 </div>
60 </SheetContent>
61</Sheet>Controlled State
Control the sheet's open state programmatically.
1
2<script lang="ts">
3 import { Sheet, SheetPrimitives, Button } from "@kareyes/aether";
4
5 const {
6 SheetContent,
7 SheetHeader,
8 SheetFooter,
9 SheetTitle,
10 SheetDescription,
11 SheetClose,
12 } = SheetPrimitives;
13
14 let openControlled = $state(false);
15</script>
16
17<div class="space-y-4">
18 <div class="flex items-center gap-4">
19 <Button onclick={() => (openControlled = true)}>
20 Open Sheet
21 </Button>
22 <Button variant="outline" onclick={() => (openControlled = false)}>
23 Close Sheet
24 </Button>
25 <span class="text-sm text-muted-foreground">
26 State: {openControlled ? "Open" : "Closed"}
27 </span>
28 </div>
29
30 <Sheet bind:open={openControlled}>
31 <SheetContent>
32 <SheetHeader>
33 <SheetTitle>Controlled Sheet</SheetTitle>
34 <SheetDescription>
35 This sheet's state is controlled programmatically.
36 </SheetDescription>
37 </SheetHeader>
38 <div class="py-4">
39 <p class="text-sm text-muted-foreground">
40 You can open and close this sheet using the buttons outside,
41 or use the close button here.
42 </p>
43 </div>
44 <SheetFooter>
45 <SheetClose>
46 <Button>Close</Button>
47 </SheetClose>
48 </SheetFooter>
49 </SheetContent>
50 </Sheet>
51</div>Custom Configurations
Advanced customization options.
Without Close Button
Custom Width
1
2<script lang="ts">
3 import { Sheet, SheetPrimitives, Button } from "@kareyes/aether";
4
5 const {
6 SheetTrigger,
7 SheetContent,
8 SheetHeader,
9 SheetFooter,
10 SheetTitle,
11 SheetDescription,
12 SheetClose,
13 } = SheetPrimitives;
14</script>
15
16<!-- Without Default Close Button -->
17<div class="space-y-2">
18 <h3 class="text-sm font-medium">Without Close Button</h3>
19 <Sheet>
20 <SheetTrigger>
21 <Button variant="outline">Important Action</Button>
22 </SheetTrigger>
23 <SheetContent>
24 <SheetHeader>
25 <SheetTitle>Confirm Action</SheetTitle>
26 <SheetDescription>
27 This action requires your confirmation.
28 </SheetDescription>
29 </SheetHeader>
30 <div class="py-4">
31 <div class="rounded-lg border border-yellow-500 bg-yellow-50 p-4 dark:bg-yellow-950">
32 <p class="text-sm font-medium">Warning</p>
33 <p class="text-sm text-muted-foreground">
34 This action cannot be undone. Please confirm to proceed.
35 </p>
36 </div>
37 </div>
38 <SheetFooter>
39 <SheetClose>
40 <Button variant="outline">Cancel</Button>
41 </SheetClose>
42 <SheetClose>
43 <Button variant="destructive">Confirm</Button>
44 </SheetClose>
45 </SheetFooter>
46 </SheetContent>
47 </Sheet>
48</div>
49
50<!-- Custom Width -->
51<div class="space-y-2">
52 <h3 class="text-sm font-medium">Custom Width</h3>
53 <Sheet>
54 <SheetTrigger>
55 <Button variant="outline">Wide Sheet</Button>
56 </SheetTrigger>
57 <SheetContent class="w-[400px] sm:w-[540px]">
58 <SheetHeader>
59 <SheetTitle>Custom Width Sheet</SheetTitle>
60 <SheetDescription>
61 This sheet has a custom width for more space.
62 </SheetDescription>
63 </SheetHeader>
64 <div class="py-4">
65 <p class="text-sm text-muted-foreground">
66 Content with more horizontal space to accommodate detailed information.
67 </p>
68 </div>
69 </SheetContent>
70 </Sheet>
71</div>Features
- 🎯 4 Side Positions: Top, Bottom, Left, Right
- ✨ Smooth Animations: Slide-in/out transitions
- 🎨 Customizable: Full control over styling and layout
- ♿ Fully Accessible: Keyboard navigation, focus management, ARIA attributes
- 🔒 Focus Trapping: Keeps focus within the sheet when open
- 🎠Overlay Backdrop: Semi-transparent overlay with click-to-close
- 🎯 Type-Safe: Full TypeScript support with Svelte 5 runes
- 🔄 Reactive: Built with Svelte 5's modern reactivity system
Implementation Details
The Sheet component is built on top of bits-ui's Dialog primitive, providing a flexible drawer/panel system.
Component Architecture
Sheet (Root)
- Root component that manages open/close state
- Controls the overall sheet behavior
- Uses bits-ui Dialog primitive
SheetTrigger
- Button or element that opens the sheet
- Automatically manages ARIA attributes
SheetContent
- Main content container with side positioning
- 4 side variants:
top,bottom,left,right - Includes close button by default
- Smooth slide animations based on side
SheetOverlay
- Semi-transparent backdrop
- Click to close functionality
- Fade in/out animations
SheetHeader
- Optional header section for title and description
- Consistent spacing and typography
SheetFooter
- Optional footer section for actions
- Flexbox layout for button groups
SheetTitle
- Accessible title for the sheet
- Connected to ARIA label
SheetDescription
- Optional description text
- Connected to ARIA description
SheetClose
- Close button component
- Can be placed anywhere within the sheet
Usage
Basic Example
<script lang="ts">
import {
Sheet,
SheetTrigger,
SheetContent,
SheetHeader,
SheetFooter,
SheetTitle,
SheetDescription,
SheetClose
} from "@kareyes/aether";
import { Button } from "@kareyes/aether";
</script>
<Sheet>
<SheetTrigger>
<Button variant="outline">Open Sheet</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="py-4">
<!-- Your content here -->
</div>
<SheetFooter>
<SheetClose>
<Button variant="outline">Cancel</Button>
</SheetClose>
<Button>Save changes</Button>
</SheetFooter>
</SheetContent>
</Sheet>
Controlled State
<script lang="ts">
import { Sheet, SheetContent, SheetTrigger } from "@kareyes/aether";
import { Button } from "@kareyes/aether";
let open = $state(false);
function handleSubmit() {
// Do something
open = false;
}
</script>
<Sheet bind:open>
<SheetTrigger>
<Button>Open</Button>
</SheetTrigger>
<SheetContent>
<form onsubmit={handleSubmit}>
<!-- Form content -->
</form>
</SheetContent>
</Sheet>
<Button onclick={() => open = true}>
Open from anywhere
</Button>
Side Positions
Right Side (Default)
<SheetContent side="right">
<!-- Content -->
</SheetContent>
Left Side
<SheetContent side="left">
<!-- Content -->
</SheetContent>
Top Side
<SheetContent side="top">
<!-- Content -->
</SheetContent>
Bottom Side
<SheetContent side="bottom">
<!-- Content -->
</SheetContent>
Advanced Examples
Form in Sheet
<script lang="ts">
import {
Sheet,
SheetTrigger,
SheetContent,
SheetHeader,
SheetTitle,
SheetDescription,
SheetFooter,
SheetClose
} from "@kareyes/aether";
import { Button } from "@kareyes/aether";
import { Input } from "@kareyes/aether";
import { Label } from "@kareyes/aether";
let name = $state("");
let email = $state("");
function handleSave() {
console.log({ name, email });
}
</script>
<Sheet>
<SheetTrigger>
<Button>Edit Profile</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 for="name" class="text-end">Name</Label>
<Input id="name" bind:value={name} class="col-span-3" />
</div>
<div class="grid grid-cols-4 items-center gap-4">
<Label for="email" class="text-end">Email</Label>
<Input id="email" type="email" bind:value={email} class="col-span-3" />
</div>
</div>
<SheetFooter>
<SheetClose>
<Button variant="outline">Cancel</Button>
</SheetClose>
<Button onclick={handleSave}>Save changes</Button>
</SheetFooter>
</SheetContent>
</Sheet>
Navigation Sheet
<script lang="ts">
import {
Sheet,
SheetTrigger,
SheetContent,
SheetHeader,
SheetTitle
} from "@kareyes/aether";
import { Button } from "@kareyes/aether";
import { Menu } from "@lucide/svelte";
const navItems = [
{ label: "Home", href: "/" },
{ label: "About", href: "/about" },
{ label: "Services", href: "/services" },
{ label: "Contact", href: "/contact" }
];
</script>
<Sheet>
<SheetTrigger>
<Button variant="ghost" size="icon">
<Menu />
</Button>
</SheetTrigger>
<SheetContent side="left">
<SheetHeader>
<SheetTitle>Navigation</SheetTitle>
</SheetHeader>
<nav class="flex flex-col gap-4 py-4">
{#each navItems as item}
<a href={item.href} class="text-lg font-medium hover:underline">
{item.label}
</a>
{/each}
</nav>
</SheetContent>
</Sheet>
Settings Sheet with Tabs
<script lang="ts">
import {
Sheet,
SheetTrigger,
SheetContent,
SheetHeader,
SheetTitle,
SheetDescription
} from "@kareyes/aether";
import { Button } from "@kareyes/aether";
import { TabsPrimitives } from "@kareyes/aether";
const { Tabs, TabsList, TabsTrigger, TabsContent } = TabsPrimitives;
import { Settings } from "@lucide/svelte";
</script>
<Sheet>
<SheetTrigger>
<Button variant="outline">
<Settings class="mr-2 size-4" />
Settings
</Button>
</SheetTrigger>
<SheetContent>
<SheetHeader>
<SheetTitle>Settings</SheetTitle>
<SheetDescription>
Manage your account settings and preferences.
</SheetDescription>
</SheetHeader>
<Tabs value="account" class="py-4">
<TabsList class="grid w-full grid-cols-2">
<TabsTrigger value="account">Account</TabsTrigger>
<TabsTrigger value="security">Security</TabsTrigger>
</TabsList>
<TabsContent value="account">
<div class="space-y-4 py-4">
<p class="text-sm text-muted-foreground">
Account settings content
</p>
</div>
</TabsContent>
<TabsContent value="security">
<div class="space-y-4 py-4">
<p class="text-sm text-muted-foreground">
Security settings content
</p>
</div>
</TabsContent>
</Tabs>
</SheetContent>
</Sheet>
Notification Sheet (Bottom)
<script lang="ts">
import {
Sheet,
SheetTrigger,
SheetContent,
SheetHeader,
SheetTitle
} from "@kareyes/aether";
import { Button } from "@kareyes/aether";
import { Bell } from "@lucide/svelte";
const notifications = [
{ id: 1, title: "New message", time: "2 min ago" },
{ id: 2, title: "Update available", time: "1 hour ago" },
{ id: 3, title: "Task completed", time: "3 hours ago" }
];
</script>
<Sheet>
<SheetTrigger>
<Button variant="outline" size="icon">
<Bell class="size-4" />
</Button>
</SheetTrigger>
<SheetContent side="bottom">
<SheetHeader>
<SheetTitle>Notifications</SheetTitle>
</SheetHeader>
<div class="space-y-4 py-4">
{#each notifications as notification}
<div class="flex items-start gap-4 border-b pb-4 last:border-0">
<div class="flex-1">
<p class="font-medium">{notification.title}</p>
<p class="text-sm text-muted-foreground">{notification.time}</p>
</div>
</div>
{/each}
</div>
</SheetContent>
</Sheet>
Without Close Button
<SheetContent hideClose>
<SheetHeader>
<SheetTitle>Important Action</SheetTitle>
<SheetDescription>
This requires your attention.
</SheetDescription>
</SheetHeader>
<div class="py-4">
<!-- Content -->
</div>
<SheetFooter>
<SheetClose>
<Button>Confirm</Button>
</SheetClose>
</SheetFooter>
</SheetContent>
Custom Width/Height
<!-- Custom width for side sheets -->
<SheetContent side="right" class="w-[400px] sm:w-[540px]">
<!-- Content -->
</SheetContent>
<!-- Custom height for top/bottom sheets -->
<SheetContent side="bottom" class="h-[400px]">
<!-- Content -->
</SheetContent>
API Reference
Sheet (Root)
Root component that manages the sheet state.
| Prop | Type | Default | Description |
|---|---|---|---|
open |
boolean |
false |
Controls the open state (bindable) |
onOpenChange |
(open: boolean) => void |
- | Callback when open state changes |
openFocus |
FocusProp |
- | Element to focus when opening |
closeFocus |
FocusProp |
- | Element to focus when closing |
portal |
HTMLElement | string |
body |
Portal target for the sheet |
SheetTrigger
Button that opens the sheet.
| Prop | Type | Default | Description |
|---|---|---|---|
ref |
HTMLButtonElement |
- | Button element reference (bindable) |
class |
string |
- | Additional CSS classes |
children |
Snippet |
- | Trigger content |
SheetContent
Main content container for the sheet.
| Prop | Type | Default | Description |
|---|---|---|---|
side |
"top" | "bottom" | "left" | "right" |
"right" |
Position of the sheet |
ref |
HTMLDivElement |
- | Content element reference (bindable) |
class |
string |
- | Additional CSS classes |
hideClose |
boolean |
false |
Hide the close button |
portalProps |
object |
- | Props for the portal component |
children |
Snippet |
- | Content to display |
SheetOverlay
Semi-transparent backdrop behind the sheet.
| Prop | Type | Default | Description |
|---|---|---|---|
ref |
HTMLDivElement |
- | Overlay element reference (bindable) |
class |
string |
- | Additional CSS classes |
SheetHeader
Container for the sheet header (title and description).
| Prop | Type | Default | Description |
|---|---|---|---|
class |
string |
- | Additional CSS classes |
children |
Snippet |
- | Header content |
SheetFooter
Container for the sheet footer (action buttons).
| Prop | Type | Default | Description |
|---|---|---|---|
class |
string |
- | Additional CSS classes |
children |
Snippet |
- | Footer content |
SheetTitle
Accessible title for the sheet.
| Prop | Type | Default | Description |
|---|---|---|---|
ref |
HTMLHeadingElement |
- | Title element reference (bindable) |
class |
string |
- | Additional CSS classes |
level |
number |
2 |
Heading level (1-6) |
children |
Snippet |
- | Title text |
SheetDescription
Description text for the sheet.
| Prop | Type | Default | Description |
|---|---|---|---|
ref |
HTMLParagraphElement |
- | Description element reference (bindable) |
class |
string |
- | Additional CSS classes |
children |
Snippet |
- | Description text |
SheetClose
Button to close the sheet.
| Prop | Type | Default | Description |
|---|---|---|---|
ref |
HTMLButtonElement |
- | Button element reference (bindable) |
class |
string |
- | Additional CSS classes |
children |
Snippet |
- | Button content |
Accessibility
The Sheet component follows WAI-ARIA dialog pattern:
Keyboard Navigation:
Escape- Close the sheetTab- Move focus forward within sheetShift + Tab- Move focus backward within sheet
Focus Management:
- Focus is trapped within the sheet when open
- First focusable element receives focus when opened
- Focus returns to trigger element when closed
ARIA Attributes:
role="dialog"on sheet contentaria-labelledbyconnects to SheetTitlearia-describedbyconnects to SheetDescriptionaria-modal="true"indicates modal behavior
Screen Readers:
- Sheet opening/closing is announced
- All interactive elements are accessible
- Proper semantic HTML structure
Best Practices
- Always include a title - Use SheetTitle for accessibility
- Provide descriptions - Use SheetDescription to explain the sheet's purpose
- Keep content focused - Sheets should have a single, clear purpose
- Use appropriate side - Right/Left for forms, Bottom for mobile notifications
- Manage state carefully - Use controlled state for complex interactions
- Avoid nesting - Don't open sheets within sheets
- Mobile considerations - Test all sides on mobile devices
- Close actions - Provide clear ways to close (SheetClose, footer buttons)
Common Use Cases
- Navigation drawer - Mobile menu (left side)
- Form panels - Edit/create forms (right side)
- Details panel - Show additional information (right side)
- Notifications - Quick view of alerts (bottom side)
- Filters - Advanced search/filter options (left/right side)
- Settings - Application configuration (right side)
- Shopping cart - E-commerce cart view (right side)
Demo & Storybook
- Demo Page:
/sheet-demo- Comprehensive examples and use cases - Storybook:
Components/Sheet- Interactive component playground
Technical Implementation
Variant System
The SheetContent component uses tailwind-variants for the side positioning system:
export const sheetVariants = tv({
base: "bg-background fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out",
variants: {
side: {
top: "inset-x-0 top-0 h-auto border-b",
bottom: "inset-x-0 bottom-0 h-auto border-t",
left: "inset-y-0 start-0 h-full w-3/4 border-e sm:max-w-sm",
right: "inset-y-0 end-0 h-full w-3/4 border-s sm:max-w-sm"
}
},
defaultVariants: {
side: "right"
}
});
Animation System
Animations are handled through Tailwind's data-attribute animation utilities:
- Slide animations based on side direction
- Smooth transitions with easing
- Configurable duration (300ms close, 500ms open)