-
Notifications
You must be signed in to change notification settings - Fork 9
Design Accessibility
Yororen UI ships a foundation in the a11y module — focus management, keyboard navigation, click-outside detection, scroll lock. The screen-reader bridge is intentionally deferred until gpui-ce ships its public AccessKit integration.
| Module | When to use |
|---|---|
a11y::focus_trap |
Modal-style overlays that must contain keyboard focus. |
a11y::click_outside |
Popovers, dropdowns, context menus that should close on outside click. |
a11y::scroll_lock |
Nested modals — prevent body scroll while a modal is open. |
a11y::keyboard_nav |
FocusableList + cycle_focus for arrow-key navigation across rows. |
All four are opt-in per element. There is no global "a11y mode".
use yororen_ui::a11y::focus_trap;
let trap = focus_trap()
.id("modal-trap")
.on_escape(|window, cx| { /* close the modal */ })
.child(modal_content);The companion FocusTrapState provides activate(window, cx) / deactivate(window, cx) — they capture and restore the focused element so a modal returns focus to its trigger when closed.
use yororen_ui::a11y::on_click_outside;
let popover_div = div()
.absolute()
.child(menu_content)
.apply(|d| on_click_outside(d, |_ev, cx| {
// popover_state.update(cx, |s, _| s.close());
}));A process-global counter that increments when acquired and decrements when dropped. RAII via Drop. Nested modals compose naturally.
use yororen_ui::a11y::ScrollLockGuard;
let _lock = ScrollLockGuard::acquire(); // body scroll now locked
// when the modal closes, `_lock` drops and the counter releasesuse yororen_ui::a11y::{cycle_focus, FocusDirection, FocusableList};
let mut list = FocusableList::new();
list.push(("row", "play"));
list.push(("row", "pause"));
list.push(("row", "stop"));
let next_id = cycle_focus(&list, current, FocusDirection::Next);
cx.focus(next_id);yororen_ui_core::a11y says it plainly: Yororen UI does not ship a screen-reader bridge on top of gpui-ce 0.3.x. The underlying gpui-ce 0.3.x release has no public API to forward ARIA roles / labels to the OS accessibility tree, and gpui-ce's in-progress branch with a full AccessKit-based bridge is not yet published.
What works today:
- Tab / Shift+Tab / arrow-key navigation.
- Escape to close overlays.
- Focus rings.
-
rolesemantics in your own code (use the right component for the job).
What doesn't work today:
- VoiceOver / NVDA / Orca announcing component roles.
- ARIA live regions.
- Structural landmarks reaching the OS accessibility tree.
Until the AccessKit bridge lands, keep semantic intent in your component tree (button not div().on_click(...), checkbox not switch, select not a hand-rolled listbox). The day the bridge lands, your app is ready without rewrites.
- Use the right component for the job. Buttons trigger actions; checkboxes toggle boolean state; selects open a listbox; modal dialogs block focus.
- Always provide stable ids for stateful elements. Tab order, focus restoration after modal close, and the future screen-reader bridge all depend on them.
-
Wire
on_escapeon overlays. Modals, popovers, dropdowns should all close on Escape. -
Acquire
ScrollLockGuardon modal open. RAII — don't forget to drop. - Test with keyboard only. No mouse. Tab through every interactive element; verify Escape closes overlays; verify arrow keys move within listbox / tree / menu.
- Keyed state — ids that drive focus.
- Layout rules — modal layering priorities.
- Recipe — Settings form — a fully keyboard-navigable 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.