-
Notifications
You must be signed in to change notification settings - Fork 9
Component Modal
MeowLynxSea edited this page Jun 13, 2026
·
7 revisions
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};use yororen_ui::headless::modal::{modal, ModalState};
use yororen_ui::headless::heading::heading;
use yororen_ui::headless::label::label;
use gpui::Entity;
let modal_state: Entity<ModalState> = cx.new(|cx| {
let mut s = ModalState::new(cx);
s.set_dismiss_on_escape(true);
s.set_dismiss_on_scrim(true);
s.set_on_close({
let entity = cx.entity();
move |_reason, _window, cx| {
entity.update(cx, |s, _cx| s.show_modal = false);
}
});
s
});
// In render, place the modal at the **scroll-root level** and wrap
// in `gpui::deferred(...).with_priority(2)` so it paints on top of
// every other element:
deferred(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))
.with_priority(2)The headless modal(id, state) factory takes the id and the state entity. The body of the modal is composed by .child(...) / .children(...) (the standard IntoElement chain). All runtime control flows through methods on the state. The methods shown below are the 6 most common.
| 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) |
Pressing Escape closes the modal. Default true. |
set_dismiss_on_scrim(v) |
Clicking the scrim closes the modal. Default true. |
set_initial_focus(h) |
Focus handle to focus when the modal opens (the renderer traps focus inside the dialog). |
set_title(t) |
Optional label, exposed to aria-modal etc. |
set_on_close(f) |
Fn(ModalCloseReason, &mut Window, &mut App) + 'static + Send + Sync. |
- Factory takes
(id, state: Entity<ModalState>). The id must be stable. -
.render(cx)is one-arg and returnsStateful<Div>. Children are added via.child(...)/.children(...)(the standardIntoElementchain). -
Placement requirement: render the modal at the scroll-root level (not inside a scrollable container) and wrap it in
gpui::deferred(...).with_priority(2). The deferred wrapper ensures the modal paints after every other element (so the scrim covers the page), andwith_priority(2)puts it on the modal layer of the priority ladder. Without the wrap, focus can leak and the scrim can render below the page content. - The renderer's animation is
AnimatedVisibility— the modal slides / fades in/out automatically based onis_open().
Popover, Drawer (planned), Form
Yororen UI v0.3.0 · repository · Apache-2.0 · This wiki documents Yororen UI v0.3.0.
This wiki documents Yororen UI v0.3.0 — the headless-core, swappable-renderer build.