Drawer
An edge-anchored panel for side drawers, filters, and quick captures.
Basic
A trigger opens the panel via data-stisla-drawer-trigger="<id>". The panel itself is a .drawer with an optional .drawer__header, a .drawer__body, and an optional .drawer__footer. The dismiss control is .drawer__close, an inline ghost icon button at the trailing edge of the header row. Default placement is the right edge.
New task
<button type="button" class="btn btn--primary" data-stisla-drawer-trigger="drawerBasic">
New task
</button>
<div class="drawer" data-stisla-drawer id="drawerBasic" aria-labelledby="drawerBasicLabel">
<div class="drawer__backdrop" data-stisla-drawer-dismiss></div>
<div class="drawer__content">
<div class="drawer__header">
<h3 class="drawer__title" id="drawerBasicLabel">New task</h3>
<button type="button" class="drawer__close" data-stisla-drawer-dismiss aria-label="Close">
<i data-lucide="x"></i>
</button>
</div>
<div class="drawer__body">
<div class="mb-4">
<label for="taskTitle" class="form-label">Title</label>
<input type="text" class="input" id="taskTitle" placeholder="Write the launch announcement">
</div>
<div class="mb-4">
<label for="taskDesc" class="form-label">Description</label>
<textarea class="textarea" id="taskDesc" rows="4" placeholder="Anything the assignee should know before they start."></textarea>
</div>
<div class="row g-3">
<div class="col-6">
<label for="taskDue" class="form-label">Due</label>
<input type="date" class="input" id="taskDue">
</div>
<div class="col-6">
<label for="taskPriority" class="form-label">Priority</label>
<select class="select" id="taskPriority">
<option>Low</option>
<option selected>Medium</option>
<option>High</option>
</select>
</div>
</div>
</div>
<div class="drawer__footer">
<button type="button" class="btn btn--ghost btn--neutral" data-stisla-drawer-dismiss>Cancel</button>
<button type="button" class="btn btn--primary" data-stisla-drawer-dismiss>Create task</button>
</div>
</div>
</div>Placements
Four modifiers anchor the panel to a viewport edge. .drawer--start slides in from the left, .drawer--end from the right, .drawer--top from above, .drawer--bottom from below. Start and end take a fixed width, top and bottom take a fixed height. Bare .drawer behaves as end.
Account
-
ProfileName, avatar, bio
-
NotificationsEmail, push, digest
-
BillingPlan, invoices, payment method
-
SecurityPassword, 2FA, sessions
Notifications
Build #2147 shipped to production in 4m 12s.
2 minutes ago"Let's pair on the cart bug tomorrow morning."
12 minutes agodb-primary-2 is at 84% used. Consider expanding the volume.
35 minutes agoWhat's new in June
Move many tasks to a new owner in one go from the board view.
Workspace search now returns results in under 100ms for most queries.
Recurring tasks no longer drift by an hour around daylight saving.
Share this report
<div class="d-flex flex-wrap gap-2">
<button type="button" class="btn btn--outline btn--neutral" data-stisla-drawer-trigger="drawerStart">Start</button>
<button type="button" class="btn btn--outline btn--neutral" data-stisla-drawer-trigger="drawerEnd">End</button>
<button type="button" class="btn btn--outline btn--neutral" data-stisla-drawer-trigger="drawerTop">Top</button>
<button type="button" class="btn btn--outline btn--neutral" data-stisla-drawer-trigger="drawerBottom">Bottom</button>
</div>
<div class="drawer drawer--start" data-stisla-drawer id="drawerStart">
<div class="drawer__backdrop" data-stisla-drawer-dismiss></div>
<div class="drawer__content">
<div class="drawer__header">
<h3 class="drawer__title">Account</h3>
<button type="button" class="drawer__close" data-stisla-drawer-dismiss aria-label="Close"><i data-lucide="x"></i></button>
</div>
<div class="drawer__body p-0">
<ul class="list-group list-group--flush">
<li class="list-group__item d-flex align-items-center gap-3">
<span class="icon-box icon-box--primary"><i data-lucide="user"></i></span>
<div class="flex-fill">
<div class="fw-medium">Profile</div>
<div class="fs-2 text-muted-foreground">Name, avatar, bio</div>
</div>
<i data-lucide="chevron-right" width="18" class="text-muted-foreground"></i>
</li>
<li class="list-group__item d-flex align-items-center gap-3">
<span class="icon-box icon-box--info"><i data-lucide="bell"></i></span>
<div class="flex-fill">
<div class="fw-medium">Notifications</div>
<div class="fs-2 text-muted-foreground">Email, push, digest</div>
</div>
<i data-lucide="chevron-right" width="18" class="text-muted-foreground"></i>
</li>
<li class="list-group__item d-flex align-items-center gap-3">
<span class="icon-box icon-box--warning"><i data-lucide="credit-card"></i></span>
<div class="flex-fill">
<div class="fw-medium">Billing</div>
<div class="fs-2 text-muted-foreground">Plan, invoices, payment method</div>
</div>
<i data-lucide="chevron-right" width="18" class="text-muted-foreground"></i>
</li>
<li class="list-group__item d-flex align-items-center gap-3">
<span class="icon-box"><i data-lucide="shield"></i></span>
<div class="flex-fill">
<div class="fw-medium">Security</div>
<div class="fs-2 text-muted-foreground">Password, 2FA, sessions</div>
</div>
<i data-lucide="chevron-right" width="18" class="text-muted-foreground"></i>
</li>
</ul>
</div>
</div>
</div>
<div class="drawer drawer--end" data-stisla-drawer id="drawerEnd">
<div class="drawer__backdrop" data-stisla-drawer-dismiss></div>
<div class="drawer__content">
<div class="drawer__header">
<h3 class="drawer__title">Notifications</h3>
<button type="button" class="drawer__close" data-stisla-drawer-dismiss aria-label="Close"><i data-lucide="x"></i></button>
</div>
<div class="drawer__body">
<div class="d-flex gap-3 mb-4 pb-4" style="border-bottom: 1px solid var(--st-border);">
<span class="icon-box icon-box--success icon-box--round flex-shrink-0"><i data-lucide="check"></i></span>
<div>
<div class="fw-medium">Deploy finished</div>
<p class="text-muted-foreground m-0 mb-1 fs-2">Build #2147 shipped to production in 4m 12s.</p>
<span class="fs-2 text-muted-foreground">2 minutes ago</span>
</div>
</div>
<div class="d-flex gap-3 mb-4 pb-4" style="border-bottom: 1px solid var(--st-border);">
<span class="icon-box icon-box--info icon-box--round flex-shrink-0"><i data-lucide="message-square"></i></span>
<div>
<div class="fw-medium">Amelia replied</div>
<p class="text-muted-foreground m-0 mb-1 fs-2">"Let's pair on the cart bug tomorrow morning."</p>
<span class="fs-2 text-muted-foreground">12 minutes ago</span>
</div>
</div>
<div class="d-flex gap-3">
<span class="icon-box icon-box--warning icon-box--round flex-shrink-0"><i data-lucide="alert-triangle"></i></span>
<div>
<div class="fw-medium">Disk above 80%</div>
<p class="text-muted-foreground m-0 mb-1 fs-2">db-primary-2 is at 84% used. Consider expanding the volume.</p>
<span class="fs-2 text-muted-foreground">35 minutes ago</span>
</div>
</div>
</div>
</div>
</div>
<div class="drawer drawer--top" data-stisla-drawer id="drawerTop" style="--drawer-height: 16rem;">
<div class="drawer__backdrop" data-stisla-drawer-dismiss></div>
<div class="drawer__content">
<div class="drawer__header">
<h3 class="drawer__title">What's new in June</h3>
<button type="button" class="drawer__close" data-stisla-drawer-dismiss aria-label="Close"><i data-lucide="x"></i></button>
</div>
<div class="drawer__body">
<div class="row g-3">
<div class="col-md-4">
<span class="badge badge--primary mb-2">New</span>
<div class="fw-medium mb-1">Bulk reassign</div>
<p class="text-muted-foreground m-0 fs-2">Move many tasks to a new owner in one go from the board view.</p>
</div>
<div class="col-md-4">
<span class="badge badge--success mb-2">Improved</span>
<div class="fw-medium mb-1">Faster search</div>
<p class="text-muted-foreground m-0 fs-2">Workspace search now returns results in under 100ms for most queries.</p>
</div>
<div class="col-md-4">
<span class="badge badge--warning mb-2">Fixed</span>
<div class="fw-medium mb-1">Recurring task DST</div>
<p class="text-muted-foreground m-0 fs-2">Recurring tasks no longer drift by an hour around daylight saving.</p>
</div>
</div>
</div>
</div>
</div>
<div class="drawer drawer--bottom" data-stisla-drawer id="drawerBottom" style="--drawer-height: 14rem;">
<div class="drawer__backdrop" data-stisla-drawer-dismiss></div>
<div class="drawer__content">
<div class="drawer__header">
<div class="mx-auto w-100 d-flex align-items-center" style="max-width: 30rem;">
<h3 class="drawer__title">Share this report</h3>
<button type="button" class="drawer__close" data-stisla-drawer-dismiss aria-label="Close"><i data-lucide="x"></i></button>
</div>
</div>
<div class="drawer__body">
<div class="mx-auto w-100" style="max-width: 30rem;">
<div class="input-group mb-4">
<input type="text" class="input" value="https://app.example.com/r/q3-revenue" readonly>
<button class="btn btn--outline btn--neutral" type="button">Copy link</button>
</div>
<div class="d-flex flex-wrap gap-2">
<button type="button" class="btn btn--outline btn--neutral"><i data-lucide="mail"></i>Email</button>
<button type="button" class="btn btn--outline btn--neutral"><i data-lucide="message-circle"></i>Slack</button>
<button type="button" class="btn btn--outline btn--neutral"><i data-lucide="download"></i>Download PDF</button>
<button type="button" class="btn btn--outline btn--neutral"><i data-lucide="printer"></i>Print</button>
</div>
</div>
</div>
</div>
</div>Sized
Override --drawer-width (start/end) or --drawer-height (top/bottom) inline on the root to retune a single instance. The default width is 22rem; this one widens to 28rem for a roomier form layout.
Edit profile
<button type="button" class="btn btn--primary" data-stisla-drawer-trigger="drawerSized">
Edit profile
</button>
<div class="drawer" data-stisla-drawer id="drawerSized" style="--drawer-width: 28rem;">
<div class="drawer__backdrop" data-stisla-drawer-dismiss></div>
<div class="drawer__content">
<div class="drawer__header">
<h3 class="drawer__title">Edit profile</h3>
<button type="button" class="drawer__close" data-stisla-drawer-dismiss aria-label="Close"><i data-lucide="x"></i></button>
</div>
<div class="drawer__body">
<div class="row g-3">
<div class="col-6">
<label for="profileFirst" class="form-label">First name</label>
<input type="text" class="input" id="profileFirst" value="Nauval">
</div>
<div class="col-6">
<label for="profileLast" class="form-label">Last name</label>
<input type="text" class="input" id="profileLast" value="Azhar">
</div>
<div class="col-12">
<label for="profileBio" class="form-label">Bio</label>
<textarea class="textarea" id="profileBio" rows="3">Designer and maintainer of Stisla.</textarea>
</div>
<div class="col-12">
<label for="profileEmail" class="form-label">Email</label>
<input type="email" class="input" id="profileEmail" value="nauvalazhar2@gmail.com">
</div>
</div>
</div>
<div class="drawer__footer">
<button type="button" class="btn btn--ghost btn--neutral" data-stisla-drawer-dismiss>Cancel</button>
<button type="button" class="btn btn--primary" data-stisla-drawer-dismiss>Save changes</button>
</div>
</div>
</div>Body scroll allowed
Set data-stisla-drawer-scroll="true" to let the page behind keep scrolling while the panel is open. Useful for activity feeds or reference panels that support the main task without interrupting it.
Activity
-
Amelia pushed 3 commits to9:42 AM
main -
Jonas completed "Audit checkout copy"9:31 AM
-
Priya commented on "Onboarding redesign"
"Step 3 looks good. The empty state on step 4 still needs a copy pass."
9:18 AM -
Lena joined the workspaceYesterday
-
Build #2143 failed onYesterday
release/v2
<button type="button" class="btn btn--primary" data-stisla-drawer-trigger="drawerActivity">
Open activity
</button>
<div class="drawer" data-stisla-drawer data-stisla-drawer-scroll="true" data-stisla-drawer-backdrop="false" id="drawerActivity">
<div class="drawer__backdrop" data-stisla-drawer-dismiss></div>
<div class="drawer__content">
<div class="drawer__header">
<h3 class="drawer__title">Activity</h3>
<button type="button" class="drawer__close" data-stisla-drawer-dismiss aria-label="Close"><i data-lucide="x"></i></button>
</div>
<div class="drawer__body">
<ol class="p-0 m-0" style="list-style: none;">
<li class="d-flex gap-3 mb-4">
<div class="icon-box icon-box--primary icon-box--round flex-shrink-0" style="--icon-box-size: 2rem;"><i data-lucide="git-commit"></i></div>
<div>
<div><span class="fw-medium">Amelia</span> pushed 3 commits to <code>main</code></div>
<span class="fs-2 text-muted-foreground">9:42 AM</span>
</div>
</li>
<li class="d-flex gap-3 mb-4">
<div class="icon-box icon-box--success icon-box--round flex-shrink-0" style="--icon-box-size: 2rem;"><i data-lucide="check"></i></div>
<div>
<div><span class="fw-medium">Jonas</span> completed "Audit checkout copy"</div>
<span class="fs-2 text-muted-foreground">9:31 AM</span>
</div>
</li>
<li class="d-flex gap-3 mb-4">
<div class="icon-box icon-box--info icon-box--round flex-shrink-0" style="--icon-box-size: 2rem;"><i data-lucide="message-square"></i></div>
<div>
<div><span class="fw-medium">Priya</span> commented on "Onboarding redesign"</div>
<p class="text-muted-foreground m-0 mb-1 fs-2">"Step 3 looks good. The empty state on step 4 still needs a copy pass."</p>
<span class="fs-2 text-muted-foreground">9:18 AM</span>
</div>
</li>
<li class="d-flex gap-3 mb-4">
<div class="icon-box icon-box--warning icon-box--round flex-shrink-0" style="--icon-box-size: 2rem;"><i data-lucide="user-plus"></i></div>
<div>
<div><span class="fw-medium">Lena</span> joined the workspace</div>
<span class="fs-2 text-muted-foreground">Yesterday</span>
</div>
</li>
<li class="d-flex gap-3">
<div class="icon-box icon-box--danger icon-box--round flex-shrink-0" style="--icon-box-size: 2rem;"><i data-lucide="alert-circle"></i></div>
<div>
<div>Build #2143 failed on <code>release/v2</code></div>
<span class="fs-2 text-muted-foreground">Yesterday</span>
</div>
</li>
</ol>
</div>
</div>
</div>Static backdrop
Set data-stisla-drawer-backdrop="static" and data-stisla-drawer-keyboard="false" to force a deliberate dismiss. The backdrop click shakes the panel along its slide axis instead of closing. Explicit dismiss controls still close.
Finish your profile
A few details so teammates know who they're working with.
<button type="button" class="btn btn--primary" data-stisla-drawer-trigger="drawerSetup">
Finish setup
</button>
<div class="drawer" data-stisla-drawer data-stisla-drawer-backdrop="static" data-stisla-drawer-keyboard="false" id="drawerSetup">
<div class="drawer__backdrop" data-stisla-drawer-dismiss></div>
<div class="drawer__content">
<div class="drawer__header">
<h3 class="drawer__title">Finish your profile</h3>
</div>
<div class="drawer__body">
<p class="text-muted-foreground">A few details so teammates know who they're working with.</p>
<div class="mb-4">
<label for="setupName" class="form-label">Full name</label>
<input type="text" class="input" id="setupName" value="Nauval Azhar">
</div>
<div class="mb-4">
<label for="setupRole" class="form-label">Role</label>
<select class="select" id="setupRole">
<option>Engineering</option>
<option selected>Design</option>
<option>Product</option>
<option>Operations</option>
</select>
</div>
<div>
<label for="setupTimezone" class="form-label">Timezone</label>
<select class="select" id="setupTimezone">
<option>UTC−05:00 New York</option>
<option>UTC+00:00 London</option>
<option selected>UTC+07:00 Jakarta</option>
<option>UTC+09:00 Tokyo</option>
</select>
</div>
</div>
<div class="drawer__footer">
<button type="button" class="btn btn--primary w-100" data-stisla-drawer-dismiss>Save and continue</button>
</div>
</div>
</div>No backdrop
Set data-stisla-drawer-backdrop="false" to drop the dim entirely so the panel sits alongside the main content. Pair with data-stisla-drawer-scroll="true" for filter panels and inspector strips the user wants to keep open while they read or click around.
Filters
<button type="button" class="btn btn--outline btn--neutral" data-stisla-drawer-trigger="drawerFilters">
<i data-lucide="filter"></i>Filters
</button>
<div class="drawer drawer--start" data-stisla-drawer data-stisla-drawer-backdrop="false" data-stisla-drawer-scroll="true" id="drawerFilters">
<div class="drawer__backdrop" data-stisla-drawer-dismiss></div>
<div class="drawer__content">
<div class="drawer__header">
<h3 class="drawer__title">Filters</h3>
<button type="button" class="drawer__close" data-stisla-drawer-dismiss aria-label="Close"><i data-lucide="x"></i></button>
</div>
<div class="drawer__body">
<div class="mb-6">
<div class="fw-medium mb-2">Status</div>
<div class="field-row">
<input class="checkbox" type="checkbox" id="fStatusOpen" checked>
<label class="field-row__label" for="fStatusOpen">Open</label>
</div>
<div class="field-row">
<input class="checkbox" type="checkbox" id="fStatusProgress" checked>
<label class="field-row__label" for="fStatusProgress">In progress</label>
</div>
<div class="field-row">
<input class="checkbox" type="checkbox" id="fStatusReview">
<label class="field-row__label" for="fStatusReview">In review</label>
</div>
<div class="field-row">
<input class="checkbox" type="checkbox" id="fStatusDone">
<label class="field-row__label" for="fStatusDone">Done</label>
</div>
</div>
<div class="mb-6">
<div class="fw-medium mb-2">Priority</div>
<div class="field-row">
<input class="checkbox" type="checkbox" id="fPriorityHigh" checked>
<label class="field-row__label" for="fPriorityHigh">High</label>
</div>
<div class="field-row">
<input class="checkbox" type="checkbox" id="fPriorityMed">
<label class="field-row__label" for="fPriorityMed">Medium</label>
</div>
<div class="field-row">
<input class="checkbox" type="checkbox" id="fPriorityLow">
<label class="field-row__label" for="fPriorityLow">Low</label>
</div>
</div>
<div>
<label for="fAssignee" class="form-label fw-medium">Assignee</label>
<select class="select" id="fAssignee">
<option selected>Anyone</option>
<option>Me</option>
<option>Amelia</option>
<option>Jonas</option>
<option>Priya</option>
</select>
</div>
</div>
<div class="drawer__footer">
<button type="button" class="btn btn--ghost btn--neutral" data-stisla-drawer-dismiss>Reset</button>
<button type="button" class="btn btn--primary" data-stisla-drawer-dismiss>Apply filters</button>
</div>
</div>
</div>Customization
Override these on the .drawer root (or globally) to retune a single instance.
Geometry
| Variable | Default | Use |
|---|---|---|
--drawer-width | 22rem | Panel width for --start and --end (default). |
--drawer-height | 16rem | Panel height for --top and --bottom. |
--drawer-padding | calc(1.25rem * var(--st-density)) | Header and body padding. Scales with --st-density. |
--drawer-z-index | 1045 | Stack level. One tier below dialog. |
Surface
| Variable | Default | Use |
|---|---|---|
--drawer-bg | var(--st-surface) | Panel fill. |
--drawer-color | var(--st-foreground) | Panel text color. |
--drawer-border-color | var(--st-border) | Inner-edge border (only the side facing the viewport). |
--drawer-shadow | 0 0 40px -10px color-mix(…) | Soft ambient shadow around the panel. |
Backdrop
| Variable | Default | Use |
|---|---|---|
--drawer-backdrop-bg | oklch(0 0 0 / 0.55) | Dim color over the page behind. |
--drawer-backdrop-blur | 12px | Backdrop blur radius. |
Title
| Variable | Default | Use |
|---|---|---|
--drawer-title-font-size | 1.125rem | Pins the title size so any heading tag reads the same. |
--drawer-title-font-weight | 600 | Title weight. |
Close chip
| Variable | Default | Use |
|---|---|---|
--drawer-close-size | 1.75rem | Width and height of the dismiss chip. |
--drawer-close-color | var(--st-muted-foreground) | Resting icon color. |
--drawer-close-color-hover | var(--st-foreground) | Hover and focus icon color. |
--drawer-close-bg-hover | var(--st-accent) | Hover and focus chip background. |
Footer
| Variable | Default | Use |
|---|---|---|
--drawer-footer-padding-y | calc(0.875rem * var(--st-density)) | Vertical padding for the footer band. |
--drawer-footer-bg | var(--st-surface-2) | Footer fill. Tints to the alt surface so the seam reads against the body. |
--drawer-footer-border-color | var(--st-border) | Top border of the footer band. |
Motion
| Variable | Default | Use |
|---|---|---|
--drawer-transition-duration | 0.25s | Slide and backdrop fade duration. Zeroed under prefers-reduced-motion: reduce. |