Drawer
A panel that slides in from the edge of the screen, with focus trapping and scroll lock.
Installation
biji-ui = { version = "0.5.0", features = ["drawer"] }
Usage
use leptos::prelude::*;
use biji_ui::components::drawer;
#[component]
pub fn MyDrawer() -> impl IntoView {
view! {
<drawer::Root>
<drawer::Trigger class="px-4 py-2 rounded-md bg-primary text-primary-foreground">
"Open Drawer"
</drawer::Trigger>
// Full-screen overlay
<drawer::Overlay
class="fixed inset-0 z-[80] bg-black/50 transition"
show_class="opacity-100 duration-300 ease-out"
hide_class="opacity-0 duration-200 ease-in"
/>
// Sliding panel
<drawer::Content
class="fixed inset-y-0 right-0 z-[90] w-80 bg-background border-l \
border-border shadow-xl transition-transform"
show_class="translate-x-0 duration-300 ease-out"
hide_class="translate-x-full duration-200 ease-in"
>
<div class="flex flex-col h-full p-6">
<drawer::Title class="text-lg font-semibold">
"Panel Title"
</drawer::Title>
<drawer::Description class="mt-1 text-sm text-muted-foreground">
"Supplementary description text."
</drawer::Description>
<div class="mt-auto">
<drawer::Close class="w-full px-4 py-2 rounded-md border">
"Close"
</drawer::Close>
</div>
</div>
</drawer::Content>
</drawer::Root>
}
}
RootWith
Use RootWith to access DrawerState inline via the let: binding. The state is Copy and safe to pass as a prop.
Drawer is closed
use leptos::prelude::*;
use biji_ui::components::drawer;
#[component]
pub fn MyDrawer() -> impl IntoView {
view! {
<drawer::RootWith let:d>
<p class="mb-2 text-sm text-muted-foreground">
{move || if d.open.get() { "Drawer is open" } else { "Drawer is closed" }}
</p>
<drawer::Trigger class="px-4 py-2 rounded-md bg-primary text-primary-foreground">
"Open Drawer"
</drawer::Trigger>
<drawer::Overlay
class="fixed inset-0 z-[80] bg-black/50 transition"
show_class="opacity-100 duration-300 ease-out"
hide_class="opacity-0 duration-200 ease-in"
/>
<drawer::Content
class="fixed inset-y-0 right-0 z-[90] w-80 bg-background border-l border-border shadow-xl transition-transform"
show_class="translate-x-0 duration-300 ease-out"
hide_class="translate-x-full duration-200 ease-in"
>
<div class="flex flex-col h-full p-6">
<drawer::Title class="text-lg font-semibold">"Settings"</drawer::Title>
<drawer::Close class="mt-auto w-full px-4 py-2 rounded-md border">
"Close"
</drawer::Close>
</div>
</drawer::Content>
</drawer::RootWith>
}
}
Examples
Side
Use the side prop on Root to control which edge the panel slides in from.
API Reference
Root / RootWith
| Name | Type | Default | Description |
|---|---|---|---|
| class | String | "" | CSS class applied to the wrapper `<div>`. |
| side | DrawerSide | Right | Which edge the panel slides in from. Sets `data-side` on Content. |
| prevent_scroll | bool | true | When true, prevents the page from scrolling while the drawer is open. |
| hide_delay | Duration | 300ms | How long to wait before unmounting Content after closing (match your CSS transition). |
| open | bool | false | Initial open state. |
| on_open_change | Option<Callback<bool>> | None | Called with `true` when opening and `false` when closing. |
Trigger
| Name | Type | Default | Description |
|---|---|---|---|
| class | String | "" | CSS class applied to the `<button>` element. |
Overlay
| Name | Type | Default | Description |
|---|---|---|---|
| class | String | "" | CSS class applied in both open and closed states. |
| show_class | String | "" | CSS class applied when the overlay is visible. |
| hide_class | String | "" | CSS class applied while the overlay is hiding. |
Content
| Name | Type | Default | Description |
|---|---|---|---|
| class | String | "" | CSS class applied in both open and closed states. |
| show_class | String | "" | CSS class applied when the panel is open (e.g. `translate-x-0`). |
| hide_class | String | "" | CSS class applied while the panel is closing (e.g. `translate-x-full`). |
Close
| Name | Type | Default | Description |
|---|---|---|---|
| class | String | "" | CSS class applied to the `<button>` element. |
Title
| Name | Type | Default | Description |
|---|---|---|---|
| class | String | "" | CSS class applied to the `<h2>` element. Its `id` is auto-wired to `aria-labelledby` on Content. |
Description
| Name | Type | Default | Description |
|---|---|---|---|
| class | String | "" | CSS class applied to the `<p>` element. Its `id` is auto-wired to `aria-describedby` on Content. |
Data Attributes
| Attribute | Description |
|---|---|
| data-state | "open" when the drawer is visible; "closed" otherwise. Present on Trigger and Content. |
| data-side | "top" | "right" | "bottom" | "left". Present on Content. |
Keyboard Navigation
| Key | Description |
|---|---|
| Tab | Moves focus to the next focusable element inside the drawer panel. |
| Shift + Tab | Moves focus to the previous focusable element inside the drawer panel. |
| Escape | Closes the drawer and returns focus to the Trigger. |