Skip to content

Component Modal

MeowLynxSea edited this page Jun 18, 2026 · 7 revisions

Modal

A dialog overlay with a scrim. The caller owns a Entity<ModalState> so it can open / close from outside.

use yororen_ui::headless::modal::{modal, ModalState};

let modal_state = ModalState::new(&mut **cx);
modal_state.update(cx, |s, _| {
    s.set_dismiss_on_escape(true);
    s.set_dismiss_on_scrim(true);
    s.set_on_close({
        let entity = cx.entity();
        move |_reason, _w, cx| entity.update(cx, |s, _| s.show_modal = false);
    });
});

modal("confirm", modal_state)
    .child(heading("confirm-title", HeadingLevel::H2, "Are you sure?", cx).render(cx))
    .child(label("confirm-body",  "This cannot be undone.", cx).render(cx))
    .render(cx)

Wrap the rendered modal in gpui::deferred(...).with_priority(2) and place it at the scroll-root level so the scrim covers every other element.

State methods

Method Purpose
new(app) Mint a fresh state. Returns Entity<Self>.
open() / close() / is_open() / is_visible() Show or hide.
set_dismiss_on_escape(v) Escape closes. Default true.
set_dismiss_on_scrim(v) Scrim click closes. Default true.
set_initial_focus(h) Focus handle to focus on open.
set_title(t) Optional label surfaced to aria-modal.
set_on_close(f) Fn(ModalCloseReason, &mut Window, &mut App) + 'static + Send + Sync.

ModalCloseReason is Escape / ScrimClick / Programmatic.

Factory takes (id, state: Entity<ModalState>). .render(cx) returns Stateful<Div>; body is added via .child(...) / .children(...).

The animation is AnimatedVisibility — the modal slides / fades in and out automatically based on is_open().

See also: Popover, Form.

Clone this wiki locally