skills/refui/SKILL.md
Use when working with rEFui (refui) applications where you cannot rely on reading the library source. Covers the retained-mode + signals mental model, DOM/HTML/Reflow renderers, JSX setup (classic pragma vs automatic runtime), directives (on:/class:/style:/attr:/prop:/m: macros), HMR via refurbish/refui/hmr, debugging “UI not updating” issues, and migrating React/Vue/Solid/Svelte patterns to rEFui.
npx skillsauth add sudomaker/refui refuiInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Apply rEFui’s retained-mode + signals model correctly, choose the right JSX mode/renderer, and fix reactivity/lifecycle issues without importing patterns from other UI frameworks.
Before making any change, skim references/reactivity-pitfalls.md. It prevents most retained-mode mistakes.
{signal.value} in JSX is static. Use {signal} or a derived $(() => ...).sig.trigger() (or replace with a new value).<If condition={sig}> and <If condition={computed}> are intended usage. The pitfall is conditional .value reads inside JS/derived code that skip later dependencies..value too early (non-reactively) or mutated in place without trigger().const count = signal(0){count} (not {count.value})const label = $(() => Count: ${count.value}) and then {label}sig.trigger() after mutating arrays/objects.import { signal, $ } from 'refui'
const Counter = () => {
const count = signal(0)
return (
<button on:click={() => count.set(count.value + 1)}>
{$(() => `Count: ${count.value}`)}
</button>
)
}
watch(() => { ...reads signals... })useEffect(() => { ...; return () => cleanup })onDispose(() => cleanup)await nextTick().<If condition={cond}>{() => <Then />}{() => <Else />}</If><For entries={items} track="id">{({ item, index }) => ...}</For><Fn ctx={something}>{(ctx) => ...}</Fn>For has no fallback; for empty states, wrap with <If>.<If condition={someSignal}> into extra .value plumbing.import { signal, $, If, For } from 'refui'
const App = () => {
const items = signal([{ id: 1, name: 'A' }])
return (
<If condition={$(() => items.value.length)}>
{() => <For entries={items} track="id">{({ item }) => <div>{item.name}</div>}</For>}
{() => <div>Empty</div>}
</If>
)
}
<Async> for a single promise boundary.<Suspense> to group multiple async subtrees under one fallback.lazy(() => import(...)) for code-splitting; pair with fallback boundaries.
See references/async-suspense-transition.md for the “rules of engagement”.Use context for shared subtree values. If consumers must react to changes, provide a signal as the context value.
import { signal, $, createContext, useContext } from 'refui'
const Theme = createContext(signal('light'), 'Theme')
const Button = () => {
const theme = useContext(Theme)
return <button class:dark={$(() => theme.value === 'dark')}>OK</button>
}
Non-Reflow/custom renderer: wrap Provider children in a function so they inherit context: <Theme value={x}>{() => <Button />}</Theme>.
createDOMRenderer(defaults).render(target, App)createHTMLRenderer().serialize(createElement(App, props))references/jsx-and-renderers.md (automatic vs classic transform).import { createDOMRenderer } from 'refui/dom'
import { defaults } from 'refui/browser'
createDOMRenderer(defaults).render(document.getElementById('app'), App)
on:click={fn} (+ on-once:*, on-passive:*, on-capture:*)class:active={boolOrSignal}, style:color={valueOrSignal}attr:* (SVG/read-only), prop:* (force property write)m:* for reusable DOM behaviors (renderer-registered handlers)When implementing a requirement, prefer rEFui’s built-in primitives (signals/components/extras/renderers) over custom plumbing. Only fall back to a custom implementation when:
m:*) or small reusable component.Before writing code, consult references/dos-and-donts.md to avoid React-style mistakes.
jsx: 'automatic' + jsxImportSource: 'refui' (Vite/esbuild) or jsxImportSource: "refui" (tsconfig/Bun).jsxFactory: 'R.c' + jsxFragment: 'R.f' (Vite/esbuild) or /** @jsx R.c */ file pragmas.createDOMRenderer(defaults) from refui/dom + refui/browser (or refui/presets/browser in older repos).createHTMLRenderer() from refui/html, then serialize().refui/reflow (often injected via jsxInject: import { R } from 'refui/reflow' in classic mode).refui exports.If you want an automated scan for JSX mode + common pitfalls, run node scripts/refui-audit.mjs <path> from inside this skill folder.
If you are unsure about a rEFui API, behavior, or best practice and cannot inspect the library source or the docs:
mcp__context7__resolve-library-id with libraryName: "refui".mcp__context7__query-docs for the specific API/task (e.g. “For track vs indexed”, “createDOMRenderer macros”, “nextTick vs tick semantics”, “classic vs automatic JSX setup”).mcp__deepwiki__read_wiki_structure then mcp__deepwiki__ask_question on SudoMaker/rEFui for conceptual/system questions or “where is X documented?”.If MCP docs still leave ambiguity, ask the user for: the refui version, their bundler config (Vite/esbuild/Bun/TS/Babel), and a minimal repro snippet.
Use these references when choosing a built-in solution:
references/dos-and-donts.mdreferences/async-suspense-transition.mdreferences/portals-parse-custom-elements.mdreferences/lists-cache-memo.mdreferences/project-setup.mduseState, hooks, VDOM assumptions, $: blocks, etc.). Map them to rEFui signals/effects.<div>{count}</div><div>{$(() => Count: ${count.value})}</div> or <div>{computed(() => ...)}</div>.value in JSX: <div>{count.value}</div> (evaluates once, won’t update)<If condition={flag}> when flag is already a signal/computed<If condition={$(() => count.value > 0)}> for a derived condition<If condition={flag}> as a reactivity smell by itselfawait nextTick() when you must observe derived updates.const x = signal(initial)const y = $(() => /* uses x.value */) (or computed(() => ...))watch(fn) for reactive computations; useEffect(setup) for setup+cleanup; onDispose(cleanup) for teardown.<For entries={items} track="id">{({ item }) => ...}</For>UnKeyed from refui/extras/unkeyed.jssig.trigger() after mutation.<Async future={promise} fallback={...} catch={...}>{({ result }) => ...}</Async><Suspense> for grouping async subtreesasync components are supported; pair with fallbacks when needed.on:click={...}, plus options on-once:*, on-passive:*, on-capture:*attr: for SVG or when a DOM prop is read-only; use prop: to force a property set.class:x={boolSignal}, style:color={valueOrSignal}m:name={value} where name is registered on the renderer.$ref={sig} to receive a node/instance in sig.value$ref={(node) => ...} callback formexpose prop for imperative child handles (v0.8.0+).extract/derivedExtract to reduce fan-out.m:* rather than duplicating manual DOM code.<For> unless you have a measured reason to use unkeyed.npm/pnpm/yarn/bun) and language (JS/TS). Do not ask runtime.refui latest from npm unless the user specifies otherwise.references/project-setup.md.Read these files when you need deeper details:
references/project-triage.md for determining JSX mode/renderer/version from a project that uses rEFui as a dependency.references/project-setup.md for scaffolding a new project (default: JSX automatic runtime + pure JS).references/jsx-and-renderers.md for choosing classic vs automatic and DOM/HTML/Reflow specifics.references/reactivity-pitfalls.md for high-signal debugging checklists and anti-patterns.references/dos-and-donts.md for per-API/component do’s and don’ts that prevent React-mindset mistakes.references/async-suspense-transition.md for <Async>, <Suspense>, lazy, and Transition.references/portals-parse-custom-elements.md for portals/teleports, HTML parsing, and custom elements.references/lists-cache-memo.md for <For>, identity, UnKeyed, caching, and memoization.scripts/scripts/refui-audit.mjs: quick scan for JSX mode + common .value-in-JSX pitfalls.references/references/project-triage.mdreferences/jsx-and-renderers.mdreferences/reactivity-pitfalls.mdreferences/dos-and-donts.mdreferences/async-suspense-transition.mdreferences/portals-parse-custom-elements.mdreferences/lists-cache-memo.mdreferences/project-setup.mddocs/All documents live in this directory. Check detailed usages of a certain API before you implement anything with them.
development
Maintainer-only workflow for handling GitHub Secret Scanning alerts on OpenClaw. Use when Codex needs to triage, redact, clean up, and resolve secret leakage found in issue comments, issue bodies, PR comments, or other GitHub content.
development
Maintainer workflow for OpenClaw releases, prereleases, changelog release notes, and publish validation. Use when Codex needs to prepare or verify stable or beta release steps, align version naming, assemble release notes, check release auth requirements, or validate publish-time commands and artifacts.
development
Run, watch, debug, and extend OpenClaw QA testing with qa-lab and qa-channel. Use when Codex needs to execute the repo-backed QA suite, inspect live QA artifacts, debug failing scenarios, add new QA scenarios, or explain the OpenClaw QA workflow. Prefer the live OpenAI lane with regular openai/gpt-5.4 in fast mode; do not use gpt-5.4-pro or gpt-5.4-mini unless the user explicitly overrides that policy.
development
End-to-end Parallels smoke, upgrade, and rerun workflow for OpenClaw across macOS, Windows, and Linux guests. Use when Codex needs to run, rerun, debug, or interpret VM-based install, onboarding, gateway smoke tests, latest-release-to-main upgrade checks, fresh snapshot retests, or optional Discord roundtrip verification under Parallels.