Props helpers
Props are the data attached to nodes: attributes, classes, styles, and events.
Props are just data
Props are structured data attached to a node. They are not magic, and they are not special-cased outside the IR. When you use props helpers, you are simply describing how a node should look and behave. The runtime reads those props and patches the DOM accordingly.
The helpers exist to keep intent clear. They tell you where attributes live, how class names are built, how style maps are applied, and how events are attached. This makes your UI tree predictable and easy to reason about.
The core helpers: attrs, cls, style
These helpers cover the most common prop categories. They are used on almost every element node.
- attrs([...]) attaches HTML attributes such as id, title, data-*, and aria-* properties.
- cls(...) controls class names. It accepts strings or expressions so you can derive classes from state.
- style([...]) applies inline styles as a map. Useful for computed values or quick demos.
Use style() for dynamic values or small adjustments, but keep most layout in CSS classes. Classes scale better as a project grows.
Events are props too
Events are attached via the on() helper. This means behavior is declared in the same prop list as attributes and classes.
An event handler is an action or a composed task, so you can treat behavior as data. This keeps structure, style, and behavior unified in the IR tree.
Reactive props and expressions
Props can be static values or expressions. When a prop depends on state, use expressions such as read(), concat(), and cond() to keep it reactive.
- read($atom) feeds state into props
- concat(...) builds attribute strings
- cond(...) chooses between class strings or style maps
A good rule is to keep props static unless they truly depend on state. It makes the IR smaller and the UI easier to debug.
Example: reactive attributes
This example shows how attrs(), cls(), style(), and on() work together. The button title updates as the count changes, which demonstrates that attributes can be driven by expressions just like text nodes.
The click handler uses inc() to update the atom, and the count display reads from the same atom, so you can see the reactive loop end to end.
Example: class strings and style maps
This component example passes class and style values as props. The template reads prop('class') and prop('style'), so the parent can fully control presentation without changing the component internals.
Notice how cond() is used to swap between class strings and style maps. This lets you build a clean, reactive styling model without mixing logic into the template.
Practical guidance
- Use attrs() for semantics and accessibility first, styling second. aria-* and data-* belong here.
- Prefer cls() over style() for layout and theming. Reserve style() for computed values or rare overrides.
- Keep reactive props focused. If a prop never changes, keep it static for clarity and performance.
- Components scale props. Pass class/style as props when you want flexible presentation without forking templates.
Props are the bridge between structure and behavior. Once you are comfortable composing them, most UI patterns become straightforward.