# Utilities Rokkit's interactivity is built on two composable primitives: **controllers** (pure state machines with no DOM dependency) and the **`navigator` Svelte action** (which binds a controller to the DOM and adds keyboard + ARIA handling). This split is what lets you test interaction logic without a browser and build your own accessible components by reusing the same controllers Rokkit uses internally. ## Controllers A controller owns the **state** of an interactive widget: - focused / selected item. - expanded set (for trees, accordions). - navigation methods (`moveNext`, `movePrevious`, `moveTo`, `moveFirst`, `moveLast`, `expand`, `collapse`, `select`). - events (`onmove`, `onselect`, `onexpand`). ```js import { ListController } from '@rokkit/states' const c = new ListController(items) c.moveFirst() // focus first c.moveNext() // focus next c.select() // select focused, fire onselect c.focusedKey // 'k_0' c.value // the selected items' raw value ``` `NestedController` adds expand / collapse semantics for trees, with tree-style behaviour built in: `expand()` on an already-expanded group focuses the first child; `collapse()` on a child focuses the parent. ## The `navigator` action `use:navigator={controller}` on any container element: - adds `keydown` handlers for arrows / Home / End / Enter / Space / Escape / typeahead. - attaches `click` handlers that read `data-path` from the target's ancestry. - writes `aria-activedescendant` / `aria-selected` / `aria-expanded` to the relevant elements. - emits `move` and `select` events you can hook into. The only contract on the markup side: each interactive row carries `data-path={node.key}`. ## Building your own component ```svelte