Skip to content
cccskills
FreePublished on GitHub

solid

Build, migrate, review, and test OpenClaw interfaces with Solid 2. The skill covers state ownership, coexistence with Lit during migration, overlays such as dialogs, performance, and checks that preserve existing interface behavior.

OriginalShow the original description

Write, refactor, review, or test Solid 2 UI in OpenClaw (Control UI, plugin views, Canvas hosts), including state ownership, native custom elements, overlays, testing, performance, and lessons learned.

See how to install

Good for

  • Migrating OpenClaw components from Lit to Solid 2
  • Reviewing state ownership and reactive updates
  • Building plugin views and dialog overlays
  • Testing UI behavior and visual parity

Files included (10)

  • SKILL.md8.3 KB
  • references/components.md4.1 KB
  • references/idioms.md21.3 KB
  • references/lessons.md12.0 KB
  • references/overlays.md4.2 KB
  • references/performance.md2.1 KB
  • references/plugins.md1.2 KB
  • references/refactor-checklist.md10.7 KB
  • references/state-and-ownership.md4.5 KB
  • references/testing.md4.5 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

Solid 2 in OpenClaw

The Control UI and plugin views (extensions/x, extensions/workboard) render with Solid 2 (solid-js, @solidjs/web, @solidjs/signals, compiled by @solidjs/vite-plugin/@solidjs/compiler). Lit and Web Awesome are removed from these surfaces; new code is Solid only. The Canvas hosts also use Solid, but the sandboxed upstream A2UI v0.8 catalog retains its separate @a2ui/lit dependency.

Read ui/AGENTS.md first; its state-ownership rules apply to Solid unchanged. Use the exact installed Solid pins from the owning package.json: the runtime and compiler are 2.0.0-rc.14, and @solidjs/vite-plugin is 3.0.0-next.49. solid-js and @solidjs/* are exempt from the repository's seven-day release-age gate (Peter, 2026-10-11); third-party Solid ecosystem packages remain subject to it.

Rules that keep the UI correct

Before your first edit, read the installed ui/node_modules/solid-js/CHEATSHEET.md, especially its "What changed from 1.x" list. It is the rc.14 API contract, written as a guard against React and Solid 1 priors, the two dominant bug sources. For new code or a Solid audit, then read idioms and lessons; to refactor or review existing code, also use the refactor checklist. Check solid-js/types/client/flow.d.ts and the installed @solidjs/signals / @solidjs/web types when choosing an API. rc.14 has no createAsync: asynchronous values are ordinary computations returning promises or async iterables.

  1. Domain owners stay plain TypeScript. The Gateway store, capabilities, lib/sessions/*, caches, persistence, and mutation authority keep synchronous mutate-then-read semantics. Solid 2 writes become visible only after a microtask flush, so authoritative state never lives in a signal. → state and ownership
  2. Components consume projections from ui/src/lib/reactive/ (one per owner and scope, never a second store) and useApplication() for the application context. Add a thin adapter only with its first production caller; subscribe to ordered events directly.
  3. Host tags and classes survive. A component renders its existing openclaw-* tag as a plain host element in light DOM; CSS and E2E select it. Never rename a tag or a class. → components
  4. One implementation per registered tag. Native custom elements and Solid callers share one renderer through defineSolidBridge in ui/src/lib/solid-bridge.ts. Use its returned component in JSX so the host has one lifecycle owner. → components
  5. One renderer per DOM region, and one lifecycle owner per overlay surface. → overlays
  6. Derive, don't synchronize. createMemo before createSignal; no copies of owner state; no defensive guards for states the owner already excludes. Prefer smaller code with fewer owners.
  7. Replace controller lifecycles at their owner. Follow the controller-to-Solid recipe, including its worked example. Delete the class and host adapter wiring together; do not wrap a controller in revision signals as the final design.

Component skeleton

An illustrative component (the tag is an example): it renders its host tag, reads an owner through a projection, and derives instead of copying state.

import { createMemo, Show } from "solid-js";
import { useApplication } from "../lib/reactive/context.ts";
import { projectAgents } from "../lib/reactive/domain-capabilities.ts";

export function AgentCount(props: { compact?: boolean }) {
  const app = useApplication();
  // Reads through to the synchronous owner; disposed with this component's owner.
  const agents = projectAgents(app.agents);
  // Never destructure props: reads must stay reactive.
  const count = createMemo(() => agents.read().agentsList?.agents.length ?? 0);
  return (
    <openclaw-agent-count class={["agent-count", { "agent-count--compact": props.compact }]}>
      <Show when={count() > 0} fallback={<span class="muted">—</span>}>
        <span>{count()}</span>
      </Show>
    </openclaw-agent-count>
  );
}

Use jsxImportSource: "@solidjs/web" and its JSX types, not Solid 1's solid-js/web.

Traps that compile but break

  • on:x, attr:x, bool:x, classList, and use: are gone in Solid 2; they compile to literal attributes or no-ops (lint flags them). prop: is the only namespace left.
  • Events are camelCase (onClick). Dashed custom events need the exact dash, such as onSession-change, or a listen(...) ref factory.
  • Native event bindings bind once: dispatch through a stable callback that reads the current handler prop. Runtime spreads, including dynamic elements, can update handlers.
  • A read right after a write sees the old value until flush(). Don't write-then-read in handlers; derive.
  • Reactive reads after the first await in an async memo are untracked, and async memos get no AbortSignal.
  • Ref callbacks run unowned: onCleanup inside them does nothing.
  • ARIA enumerations are typed strings: aria-pressed={pressed() ? "true" : "false"}, never a boolean.
  • Solid 1 APIs (createResource, onMount, mergeProps, Context.Provider) don't carry over: use async computations, onSettled, merge, and the context component itself.
  • Writing a signal or store from a memo, an effect compute phase, or a component body throws in dev. untrack doesn't exempt it (the guard checks the owner); derive instead, or write from a handler, onSettled, or effect apply.
  • Class strings built with template literals or .filter(Boolean).join(" ") lose composable reactivity: use class={["base", { active: active() }]}.
  • createRenderEffect is for render-phase runtime bindings, and flush() in production code usually hides a write-then-read: feature code uses createEffect and derivations.

More, each with its root cause: lessons learned.

Testing

mountSolid, waitForSolid/flush, renderSolidRef, and the Solid application-context provider live in ui/src/test-helpers/. .test.tsx files are discovered. Keep assertions when you replace a harness. Visual changes need inspected, sanitized before/after screenshots. Follow the assigned campaign's compute budget. → testing

References

TopicRead when
idiomschoosing a primitive, derivations, props, lifecycle, stores, keys, async, context, diagnostics
refactor checklistrefactoring or reviewing existing Solid: measurable smells, replacements, before/after
componentswriting components, native custom-element hosts, JSX bindings, events, refs, styles
state and ownershiptouching owners, projections, async reads, lifetimes, parking, chat render lifecycle
overlaysmenus, popovers, tooltips, dialogs, focus, positioning, the platform floor
testingunit, browser, E2E, WebKit, parity, retention suites
performancestartup bundle, lazy loading, render budgets
pluginsbuilding a plugin's Control UI view in Solid
lessons learnedbefore a new kind of change; most entries cost a failed CI run to learn

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

1password

FreeSummary

Set up and authenticate the 1Password CLI, then supply stored passwords and API keys to commands or configuration. The skill covers desktop integration, service accounts, and interactive sign-in while keeping secrets out of chat and logs.

  • Setting up the 1Password CLI
  • Supplying API keys to commands
  • Using service account authentication in CI
openclaw/openclaw392.4KUpdated Oct 18, 2026

acp-router

FreeSummaryAI rating 80

Route requests from OpenClaw to external coding agents such as Claude Code or Cursor. Start or continue sessions using ACP, a protocol for connecting agents, or relay prompts directly through acpx while preserving conversation context.

  • Starting a Claude Code session in a thread
  • Continuing work with an external coding agent
  • Relaying prompts directly through acpx
openclaw/openclaw392.4KUpdated Oct 18, 2026

Add a model provider to OpenClaw and verify it with a real response. The skill validates configuration, keeps credentials in environment or file references, and reports test results and any default model changes.

  • Adding a model provider to OpenClaw
  • Configuring credentials through environment or file references
  • Checking whether a model returns a real response
openclaw/openclaw392.4KUpdated Oct 18, 2026

agent-transcript

FreeSummary

Prepare an agent activity transcript for a GitHub pull request or issue. Extract relevant prompts, decisions, and results from local logs, remove sensitive material, and preview the edited record before separately authorized publication.

  • Preparing an agent activity record for a pull request
  • Extracting task-relevant prompts and results from local logs
  • Previewing a transcript with sensitive information removed
openclaw/openclaw392.4KUpdated Oct 18, 2026

apple-notes

FreeSummary

Manage Apple Notes on macOS through memo, a command-line tool. Create, browse, search, edit, delete, and move notes between folders, or export selected notes to HTML or Markdown for use outside the app.

  • Creating notes with titles
  • Finding notes by folder or approximate search
  • Editing notes and organizing them into folders
openclaw/openclaw392.4KUpdated Oct 18, 2026

apple-reminders

FreeSummary

Manage Apple Reminders from your Mac with remindctl, a terminal tool. View tasks by date, add or edit reminders, organize lists, and mark tasks complete or delete them, including personal to-dos that sync to iOS.

  • Review today’s tasks and overdue reminders
  • Add personal to-dos with due dates
  • Organize tasks visible on an iPhone or iPad
openclaw/openclaw392.4KUpdated Oct 18, 2026

See all skills by openclaw

Report a problem with this skill