Skip to content
Glint UI

Drawer

A modal surface anchored to the bottom of the screen with a grab handle and drag-to-dismiss gesture.

Usage

import { Drawer } from "@glint/components/drawer.slint";
export component AppWindow inherits Window {
in-out property <bool> show-drawer: false;
callback log-closed();
VerticalLayout {
// your screen layout
}
// Last child of the window, sized to it: Slint has no portals, so what
// draws on top is what comes last.
Drawer {
width: parent.width;
height: parent.height;
panel-extent: 320px;
open <=> root.show-drawer;
title: "Filters";
description: "Configure view options.";
dismissed => { root.log-closed(); }
}
}

Drawer is a bottom-anchored modal surface designed for gesture-friendly interactions. It features a drag handle at the top and supports drag-to-dismiss gestures alongside standard backdrop and keyboard dismissal.

Mount it last among the window’s children, sized to width: parent.width; height: parent.height.

Examples

Snap points

snap-points accepts an array of fractions of panel-extent (in ascending order) where the drawer can rest. Dragging between snap points snaps to the closest threshold and reports the new index through current-snap and snap-changed(int).

Non-modal drawer

Setting modal: false removes the backdrop scrim entirely, allowing users to interact with the underlying interface while the drawer remains open.

Nested drawers

Stacking multiple drawers is supported through nested-open. When a child drawer opens, the parent drawer dims its own backdrop and slides down slightly (nested-inset) so the pair reads as a depth stack.

Restoring focus

restore-focus fires whenever the drawer closes, allowing keyboard focus to return cleanly to the opening button.

API Reference

Properties

PropertyTypeDefaultDescription
openin-out boolfalseTwo-way; consumer sets true to slide up, Drawer sets false on close.
titlein stringno defaultHeading inside the drawer.
descriptionin stringno defaultBody text under the title.
dismiss-on-backdropin booltrueWhen true, clicking the backdrop closes the drawer.
modalin booltrueWhen false the drawer renders no backdrop at all, so the application behind it keeps its pointer events (shadcn's non-modal drawer). An open Scrim installs a full-window TouchArea, so suppressing it is the only way the content underneath stays live.
panel-extentin length360pxHeight of the panel; the drawer always spans the window's width.
snap-pointsin [float][]Heights the drawer can come to rest at, as fractions of panel-extent, in ascending order. Empty (the default) means one resting height — the full extent — and the drag stays the two-outcome gesture it always was.
current-snapin-out int0Index into snap-points of the height the drawer is resting at. Two-way: the consumer picks the opening height, and a settled drag writes back the one it landed on.
nested-openin boolfalseTrue while another Drawer is open on top of this one. Set it from the child's open — one line, the way ADR-0006 wires every trigger. The stack then shows a single backdrop (this one stands its own down) and this panel insets behind the child instead of doubling the dim.
nestedout boolno defaultTrue while this drawer is open with something stacked on it — the styling hook vaul spells data-nested-drawer-open.
drag-offsetout lengthno defaultHow far the panel is currently dragged below its resting position; zero unless a drag is in flight. Public because the gesture's progress is the one piece of drawer state a consumer cannot derive.

Callbacks

CallbackDescription
dismissed()Fired when the drawer closes itself — backdrop, Escape or drag.
snap-changed(int)Fired when a settled drag comes to rest at a different snap point, with its index. current-snap already carries the new value.
restore-focus()Fired on EVERY close, including one the consumer drives by setting open = false, so keyboard focus always gets a new home: restore-focus => { my-button.focus(); }. Slint exposes no "previously focused element", so only the trigger's owner can name it.

Accessibility

  • Role and name. The open drawer card claims a region landmark named by title and described by description.
  • Grab handle. A pill-shaped grab indicator at the top of the panel provides a clear visual affordance for the drag gesture, backed by a generous touch grab target.
  • Keyboard navigation. Escape dismisses the open drawer and calls dismissed().
  • Focus restoration. Every close path — backdrop click, drag release past the dismiss threshold, Escape, or programmatic close — invokes restore-focus() to return focus to the trigger.
  • Non-modal accessibility. With modal: false, the scrim TouchArea is removed so screen readers and keyboard users can continue accessing the application content behind the drawer.
  • The trigger. Controls that open a drawer should declare haspopup: true.