Common Patterns

Rendering lists, conditionals, and other patterns you'd reach for in Vue/React — translated to ERB.

Conditional rendering

Vue uses v-if. React uses ternaries or early returns. In ERB, it’s just Ruby:

Vue / React

<Badge v-if="user.admin" color="warning">
  Admin
</Badge>

{user.admin && <Badge color="warning">Admin</Badge>}

Kiso

<%% if user.admin? %>
  <%%= kui(:badge, color: :warning) { "Admin" } %>
<%% end %>

Rendering lists

Vue uses v-for. React uses .map(). In ERB, use .each:

<% @users.each do |user| %>
  <%= kui(:badge, color: user.role_color) { user.name } %>
<% end %>

For components that support it, Kiso also has a collection: shorthand:

<%= kui(:badge, collection: @tags) %>

Dynamic props

Compute locals from your data just like you would with dynamic props:

<%= kui(:alert,
    color: flash_type == "notice" ? :success : :error,
    variant: :soft) do %>
  <%= kui(:alert, :title) { flash_type.capitalize } %>
  <%= kui(:alert, :description) { flash_message } %>
<% end %>

Composing components together

Build complex UI by nesting components. This Card with a list of Badges is the same pattern as nesting React or Vue components:

<%= kui(:card) do %>
  <%= kui(:card, :header) do %>
    <%= kui(:card, :title) { "Team Members" } %>
    <%= kui(:card, :description) { "People with access to this project." } %>
  <% end %>
  <%= kui(:card, :content) do %>
    <%= kui(:table) do %>
      <%= kui(:table, :header) do %>
        <%= kui(:table, :row) do %>
          <%= kui(:table, :head) { "Name" } %>
          <%= kui(:table, :head) { "Role" } %>
        <% end %>
      <% end %>
      <%= kui(:table, :body) do %>
        <% @members.each do |member| %>
          <%= kui(:table, :row) do %>
            <%= kui(:table, :cell) { member.name } %>
            <%= kui(:table, :cell) do %>
              <%= kui(:badge, color: member.role_color, size: :sm) { member.role } %>
            <% end %>
          <% end %>
        <% end %>
      <% end %>
    <% end %>
  <% end %>
<% end %>

Stimulus for interactivity

Where Vue/React use state and event handlers, Kiso uses Stimulus controllers:

<%= kui(:button,
    data: { controller: "clipboard", action: "click->clipboard#copy",
            clipboard_content_value: invite_url }) do %>
  Copy invite link
<% end %>

The component handles the HTML and styling. The Stimulus controller handles behavior. They’re separate concerns — you can swap the component’s appearance without touching the JS, or reuse the controller on a completely different element.