CO

control-flow

Provides reactive UI helpers for rendering lists and conditional components in a performant way.

Install

mkdir -p .claude/skills/control-flow-yw662 && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/16055" && unzip -o skill.zip -d .claude/skills/control-flow-yw662 && rm skill.zip

Installs to .claude/skills/control-flow-yw662

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Reactive ranges for lists and conditionals — `For` (lists), `Show` (visibility), `When` (binary branches), `Switch` / `Match` (multi-way). Load this when the task is about rendering a list of items, conditionally showing/hiding elements, or pattern-matching on a value to render different branches.
298 chars✓ has a “when” triggerlonger than Claude Code's old 250-char listing cap (fine on current versions)
Intermediate

Key capabilities

  • Render lists from signals
  • Toggle element visibility based on a signal
  • Implement two-branch conditionals
  • Implement multi-way matching with cached DOM
  • Nest control flow helpers

How it works

It provides reactive range helpers (For, Show, When, Switch, Match) that cache their DOM elements, updating them based on signal changes without rebuilding.

Inputs & outputs

You give it
Signal.State or Signal.Computed, render functions, optional keyFn or matcher
You get back
ReactiveRange (DOM elements) that updates based on signal changes

When to use control-flow

  • Rendering lists dynamically
  • Toggling visibility of components
  • Conditional UI rendering

About this skill

Control Flow

rikka-dom ships four reactive range helpers: For for lists, Show for visibility, When for binary branches, Switch / Match for multi-way. All cache their DOM so toggling does not rebuild elements.

Imports

import { For, Show, When, Switch, Match } from "@takanashi/rikka-dom";

For(source, render, keyFn?): ReactiveRange

Render a list from a Signal.State<T[]> or Signal.Computed<T[]>. Returns a range you can mount anywhere Child is accepted.

import { signal } from "@takanashi/rikka-signal";
import { For, li } from "@takanashi/rikka-dom";

const items = signal(["a", "b", "c"]);
const list = For(items, (item) => li({}, item));

Keyed rendering

Pass a keyFn to cache DOM by key, so updates only add/remove the changed items:

const users = signal([{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }]);

For(
  users,
  (user) => li({}, user.name),
  (user) => user.id, // keyFn
);

Without a keyFn, caching is by reference (Object.is). Unused cached entries are cleaned up on each re-evaluation.

Show(condition, render): ReactiveRange

Toggle visibility based on a signal. The element is created once and shown/hidden on subsequent toggles.

import { signal } from "@takanashi/rikka-signal";
import { Show, span } from "@takanashi/rikka-dom";

const visible = signal(true);

Show(visible, () => span({}, "visible"));
// visible.set(false) → element removed from DOM
// visible.set(true)  → same element re-inserted

When(condition, trueRender, falseRender): ReactiveRange

Two-branch conditional. Both branches are cached.

import { signal } from "@takanashi/rikka-signal";
import { When, span } from "@takanashi/rikka-dom";

const loggedIn = signal(false);

When(
  loggedIn,
  () => span({}, "Welcome!"),
  () => span({}, "Please log in"),
);

Switch(value, ...cases) and Match(matcher, render)

Multi-way matching. Each case DOM is cached. The first matching case is shown.

import { signal } from "@takanashi/rikka-signal";
import { Switch, Match, textarea, div } from "@takanashi/rikka-dom";

const mode = signal("edit");

Switch(
  mode,
  Match("edit", () => textarea()),
  Match("preview", () => div({}, "Preview")),
  Match(
    (v) => v.startsWith("admin"),  // predicate form
    () => div({}, "Admin"),
  ),
);

Match's matcher is either:

  • A value — compared with Object.is
  • A predicate function (value: T) => boolean

The last case acts as a fallback (no matcher, or always-true predicate).

Nesting control flow

For / Show / When / Switch return a ReactiveRange, which is a valid Child. Compose freely:

For(todos, (todo) =>
  Show(todo.done, () => s({}, todo.text), () => s({}, todo.text, " ✓"))
);

Pitfalls

1. Plain array instead of signal

// ❌ Static — list never updates
For(["a", "b", "c"] as any, (x) => li({}, x));

// ✅ Signal — list updates
For(signal(["a", "b", "c"]), (x) => li({}, x));

(rikka's type system catches this — source must be a Signal.State<T[]> or Signal.Computed<T[]>.)

2. Forgetting keyFn on a list with stable IDs

Without keyFn, caching is by reference. If your data is replaced wholesale (e.g. fetched fresh from an API), every item will be re-rendered. Use keyFn whenever your items have a stable identity:

// Without keyFn: full re-render on each refresh
For(users, (u) => li({}, u.name));

// With keyFn: only changed items re-render
For(users, (u) => li({}, u.name), (u) => u.id);

3. Forgetting () after () => in Match

Switch(mode,
  Match("edit", () => textarea()),  // ✅ render function called
  Match("preview", textarea),       // ❌ passes the function reference, not its result
);

Always invoke the render function with ().

4. Using Show for two branches

// ❌ Awkward — two `Show` blocks
Show(cond, () => A());
Show(computed(() => !cond.get()), () => B());

// ✅ Use `When`
When(cond, () => A(), () => B());

See also

When not to use it

  • When using a plain array instead of a signal for lists
  • When using `Show` for two branches instead of `When`
  • When forgetting `keyFn` on a list with stable IDs

Limitations

  • Forgetting `keyFn` on a list with stable IDs will cause full re-render on each refresh
  • Match render functions must be invoked with `()`
  • Using `Show` for two branches is awkward compared to `When`

How it compares

This skill offers specialized components for reactive UI rendering that optimize performance by caching DOM elements, unlike manual conditional rendering that might rebuild elements.

Compared to similar skills

control-flow side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
control-flow (this skill)02moNo flagsIntermediate
zustand1132moNo flagsIntermediate
threejs-skills614moNo flagsIntermediate
accessibility-compliance452moNo flagsIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

You might also like

zustand

lobehub

Zustand state management guide. Use when working with store code (src/store/**), implementing actions, managing state, or creating slices. Triggers on Zustand store development, state management questions, or action implementation.

113434

threejs-skills

sickn33

Three.js skills for creating 3D elements and interactive experiences

61152

accessibility-compliance

wshobson

Implement WCAG 2.2 compliant interfaces with mobile accessibility, inclusive design patterns, and assistive technology support. Use when auditing accessibility, implementing ARIA patterns, building for screen readers, or ensuring inclusive user experiences.

45132

react-modernization

wshobson

Upgrade React applications to latest versions, migrate from class components to hooks, and adopt concurrent features. Use when modernizing React codebases, migrating to React Hooks, or upgrading to latest React versions.

21134

3d-graphics

samhvw8

3D web graphics with Three.js (WebGL/WebGPU). Capabilities: scenes, cameras, geometries, materials, lights, animations, model loading (GLTF/FBX), PBR materials, shadows, post-processing (bloom, SSAO, SSR), custom shaders, instancing, LOD, physics, VR/XR. Actions: create, build, animate, render 3D scenes/models. Keywords: Three.js, WebGL, WebGPU, 3D graphics, scene, camera, geometry, material, light, animation, GLTF, FBX, OrbitControls, PBR, shadow mapping, post-processing, bloom, SSAO, shader, instancing, LOD, WebXR, VR, AR, product configurator, data visualization, architectural walkthrough, interactive 3D, canvas. Use when: creating 3D visualizations, building WebGL/WebGPU apps, loading 3D models, adding animations, implementing VR/XR, creating interactive graphics, building product configurators.

33104

d3-visualization

lyndonkl

Use when creating custom, interactive data visualizations with D3.js—building bar/line/scatter charts from scratch, creating network diagrams or geographic maps, binding changing data to visual elements, adding zoom/pan/brush interactions, animating chart transitions, or when chart libraries (Highcharts, Chart.js) don't support your specific visualization design and you need low-level control over data-driven DOM manipulation, scales, shapes, and layouts.

7107

Search skills

Search the agent skills registry