Thinking in Partials
How Kiso components work if you're coming from Vue or React.
If you’re coming from Vue or React, Kiso components will feel familiar — but the mechanics are different. This guide maps the concepts you already know to how things work in ERB.
Components are templates, not classes
A Vue SFC or React component is a unit of code that manages state, renders UI, and hooks into a lifecycle. A Kiso component is simpler: it’s an ERB partial that receives locals and produces HTML. No instances, no lifecycle, no re-renders.
Vue
<Badge color="primary">New</Badge>
Kiso
<%%= kui(:badge, color: :primary) { "New" } %>
kui() is Kiso’s render helper. It finds the right partial, passes your
locals, and returns HTML. Think of it as a function call that returns markup —
because that’s exactly what it is.
The kui() helper
Every component renders through kui():
<% # Component with a block %>
<%= kui(:badge, color: :success) { "Active" } %>
<% # Component with sub-parts %>
<%= kui(:card) do %>
<%= kui(:card, :header) do %>
<%= kui(:card, :title) { "Settings" } %>
<% end %>
<% end %>
The first argument is always the component name. An optional second argument selects a sub-part. Everything else is a local passed to the partial.
No virtual DOM, no reactivity
In React, changing state triggers a re-render. In Vue, reactive data updates the DOM automatically. Kiso doesn’t do either — the server renders HTML once and sends it to the browser.
For interactivity, Kiso uses:
- Native HTML5 —
<dialog>,[popover],<details>handle most UI patterns without any JavaScript - Stimulus — lightweight controllers for behavior that HTML can’t express (toggling, animations, async loading)
This is a different mental model. Instead of “how do I make this component react to state changes?”, think “how do I make the server send the right HTML, and what browser-native features handle the rest?”