Skip to content

Components

MeowLynxSea edited this page Jun 18, 2026 · 15 revisions

Components

Every component lives in yororen-ui-core/src/headless/ as a factory function returning a XxxProps builder. Every factory has a .render(cx) (or .render(cx, window) for text inputs) method that resolves through cx.renderer_arc::<markers::Xxx, dyn XxxRenderer>() and applies the registered TokenXxxRenderer for the default look.

The flat top-level import yororen_ui::headless::button is sugar: headless/mod.rs does pub use button::button; so callers can write use yororen_ui::headless::button; and get the factory function directly. The fully-qualified form yororen_ui::headless::button::button is the canonical path when there is any naming-collision risk.

use yororen_ui::headless::button::button;
use yororen_ui::headless::virtual_list::{
    uniform_virtual_list, virtual_list,
    UniformVirtualListController, VirtualListController,
};
use yororen_ui::headless::markers;     // marker types for cx.renderer_arc::<...>()

The factory + .render(cx) pattern

// Pure headless — the caller composes the visuals.
div().bg(red).rounded(8).apply(button("save", cx).on_click(...)).child("Save")

// Default-rendered look from the installed theme + TokenXxxRenderer.
button("save", cx).on_click(...).render(cx).child("Save")

State ownership

For composites that own interaction state (Modal, Select, Popover, DropdownMenu, Tooltip, ComboBox, Listbox, Menu, Tree, Table, VirtualList, Form), the factory returns a props builder; the actual state entity lives elsewhere and is wired through:

  • cx.entity().clone() — the canonical way to hand a callback a handle to your own Entity<MyState>.
  • cx.new(|_| XxxState::new()) — mint the component's own state entity.

The component owns interaction state (caret, selection, scroll, animation, open/closed). Your app owns business state (text, validation, submit status). on_change is the only bridge.

Picking the right component

  • Select vs ComboBox — use Select for small option sets (< ~20); use ComboBox for large sets that benefit from search.
  • Checkbox vs Switch — both are boolean toggles; use Switch for settings-style toggles.
  • Button vs a raw div with .on_click(...) — use Button for semantic actions; for a non-button clickable surface just wire .on_click(...) directly.
  • Popover vs DropdownMenuPopover is an anchored content surface; DropdownMenu adds menu-item navigation and keyboard handling.

Component index

Foundation

Action surfaces

Inputs

List / data

Overlays

Progress / status

One-time startup calls

Some composites need a one-time registration at app startup:

yororen_ui::headless::text_input::init(cx);

This binds the keymap for the seven text inputs against the UITextInput context. It is idempotent (a OnceLock inside the crate) — calling it more than once is safe.

Marker types

cx.renderer_arc::<markers::Xxx, dyn XxxRenderer>() is the lookup key for the per-component renderer. markers is re-exported at yororen_ui::headless::markers. The 55 markers are defined in yororen-ui-core::renderer::markers.

What's not in yororen-ui-core::headless

  • Widgets — see Widgets. Only VirtualList ships as a widget.
  • NotificationCenter — the data + state machine lives in yororen_ui::notification::* (Notification, NotificationCenter, NotificationId, DismissStrategy, ToastKind). The visual host is not shipped — implement it in your app.
  • Theme / i18n / rtl / a11y / animation / assets — sibling top-level modules in yororen_ui. Cross-cutting, not components.

Clone this wiki locally