# Mixins, Styling, and Events ## What This Covers How to attach behavior, styles, and DOM-aware setup to host elements with `mix`. Read this when the task involves: - DOM event handling with `on(...)` - Static styling with `css(...)` and dynamic styling with `style` - Imperative DOM access via `ref(...)` - Navigation behavior on non-anchor elements with `link(...)` - Native click, pointer, and keyboard behavior with `on(...)`, plus attributes with `attrs(...)` - Element-level animation mixins from `remix/ui/animation` For richer animation work (springs, tweens, layout transitions), see `animate-elements.md`. For authoring custom mixins, see `create-mixins.md`. For component lifecycle and updates, see `component-model.md`. Compose behavior on host elements with `mix`. Pass a single mixin directly (`mix={on(...)}`), or an array when composing multiple mixins (`mix={[css(...), on(...)]}`). Core mixins are imported from `remix/ui`; animation mixins are imported from `remix/ui/animation`. ## `on(type, handler, capture?)` Attaches a typed DOM event handler. The handler receives the event and an `AbortSignal` that aborts when the handler is re-entered or the component is removed — this prevents race conditions: ```tsx { let query = event.currentTarget.value loading = true handle.update() let response = await fetch(`/search?q=${query}`, { signal }) let data = await response.json() if (signal.aborted) return results = data.results loading = false handle.update() })} /> ``` Multiple events on the same element: ```tsx
{ event.preventDefault() let formData = new FormData(event.currentTarget) })} > ``` ## `css(styles)` Applies generated class names for CSS object styles. Produces static CSS rules inserted into the document. Supports pseudo-selectors, pseudo-elements, attribute selectors, descendant selectors, and media queries using `&` to reference the current element: ```tsx ``` For gesture-specific behavior, compose the pointer or keyboard events the interaction actually needs: ```tsx
{ if (event.key === 'Escape') close() if (event.key === 'Enter' || event.key === ' ') doAction() })} /> ``` ## `attrs()` Sets HTML attributes through the mixin system. ## Animation Mixins ### `animateEntrance(config)` Animates an element when it is inserted into the DOM. Config specifies the **starting** style: ```tsx
``` ### `animateExit(config)` Animates an element when it is removed. Config specifies the **ending** style. The element is kept in the DOM until the animation completes: ```tsx { isVisible && (
) } ``` ### `animateLayout(config?)` Animates layout changes (position/size) using FLIP-style transforms: ```tsx { items.map((item) => (
  • )) } ``` Options: `duration` (default 200ms), `easing` (default spring snappy), `size` (boolean, default true — include scale projection for size changes). Always key elements you expect to animate. Use `...spring(preset)` to spread `duration` and `easing` into any animation config.