Drawer

Drawer is a full-height side panel that appears above the main screen.
Use it when you need temporary space for navigation, filters, settings, or an inspector without changing the main route. The important architectural rule is that the drawer does not decide when it is open. Your app state owns that decision through is_open. The widget's job is to render the panel into the modal portal layer, add a backdrop, and dispatch your dismiss action when the backdrop is tapped.
This makes the behavior predictable. A button dispatches an action, the reducer flips show_filters to true, and the next component conversion pass includes an open drawer. Closing the drawer is the same loop in reverse.
Do not use a drawer for critical confirmations or short blocking decisions. That is usually a Modal. Also do not use it for tiny anchored choices next to a button. That is what Popover or flyout are for.

Example

use fission::prelude::*;

let drawer = Drawer {
    id: WidgetId::explicit("filters_drawer"),
    side: DrawerSide::Right,
    is_open: view.state().show_filters,
    on_dismiss: Some(ctx.bind(
        ToggleFilters(false),
        reduce_with!((|state: &mut GlobalState, action: ToggleFilters, _| {
            state.show_filters = action.0;
        })),
    )),
    width: Some(360.0),
    content: 
        VStack {
            spacing: Some(16.0),
            children: vec![filter_form.into()],
        }
        .into(),
    ,
}
.into();
The reducer owns show_filters. The drawer itself only reads that state and emits on_dismiss when the user taps the backdrop.

Field table

Field
Type
Meaning
Notes / default behavior
id
WidgetId
Stable identity for the portal entry.
Required. Give each drawer a stable id so the runtime can track it consistently.
side
DrawerSide
Which horizontal edge the panel attaches to.
Use Left or Right.
is_open
bool
Whether the drawer should be visible this frame.
When false, the widget returns an inert spacer and registers no portal.
on_dismiss
Option<ActionEnvelope>
Action dispatched when the backdrop is tapped.
Defaults to None. If you omit it, the backdrop still covers the screen but does not close the drawer for you.
content
Widget
The panel body.
Build the full drawer user interface here.
width
Option<f32>
Requested panel width in logical pixels.
Defaults to 300.0. The runtime clamps it to the current viewport so the drawer still fits on smaller screens.

Layout and overlay behavior

When open, Drawer registers a portal in PortalLayer::Modal. The shell wraps portal content in a viewport-sized container, so the drawer always measures against the whole screen instead of the inline spot where the widget was declared.
The panel itself is pinned to the chosen edge and stretches from top to bottom. The backdrop covers the full viewport behind it. This means the screen under the drawer is visually present but not the place where the user should continue interacting.

Specific advice

Put only temporary, secondary user interface in a drawer. If people need to finish a task before they can continue, use a modal dialog instead. If the panel is always visible on large screens, consider a normal layout widget such as SplitView, Row, or Column instead of opening and closing an overlay.
Also note that the current implementation does not animate the drawer sliding in or out by itself. It appears and disappears as state changes. If motion is important to your product, treat that as an explicit design decision and test the chosen pattern carefully.

Production checklist

For Drawer, review the fields that change behavior before treating the widget as finished: id, side, is_open, on_dismiss, content, width. The goal is to make the product rule visible in state and actions, not hidden inside ad-hoc construction code.
Bind on_dismiss to explicit reducer actions and test that the reducer handles unavailable, duplicate, or invalid input safely.
When child widgets are generated from data, give reordered or filtered rows an explicit WidgetId so retained local state and scroll behavior do not drift between items.
Set id only when identity must be stable across filtering, reordering, diagnostics, or tests; otherwise let Fission derive identity from structure.
Check the semantics tree for the user-facing label or role that makes this widget understandable without relying only on pixels.
Prefer parent layout and design-system sizing first; use explicit size or spacing fields when the product layout requires that constraint on this widget specifically.
Add at least one component or harness test that confirms the visible text, semantic role, action dispatch, and layout constraint that matter for this widget in context.
If a screen starts repeating the same Drawer setup, extract a named component around this widget. That keeps the reference API small while making product code easier to read and safer for generated code to copy.
DrawerSide, Modal, Popover, Portal, and SafeArea.
Fission
A cross-platform, GPU-accelerated user interface framework for Rust. MIT licensed.
Copyright (c) 2026 Fission
Ready to use today. Widget APIs are expected to remain stable; some runtime and shell APIs may change before 1.0.0.
Fission 0.7.0