Back to skills
SkillHub ClubShip Full StackFull StackFrontend

solidjs-patterns

SolidJS reactivity + UI state patterns for OpenWork

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
11,961
Hot score
99
Updated
March 20, 2026
Overall rating
C5.0
Composite score
5.0
Best-practice grade
B81.2

Install command

npx @skill-hub/cli install different-ai-openwork-solidjs-patterns

Repository

different-ai/openwork

Skill path: .opencode/skill/solidjs-patterns

SolidJS reactivity + UI state patterns for OpenWork

Open repository

Best for

Primary workflow: Ship Full Stack.

Technical facets: Full Stack, Frontend.

Target audience: everyone.

License: Unknown.

Original source

Catalog source: SkillHub Club.

Repository owner: different-ai.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install solidjs-patterns into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/different-ai/openwork before adding solidjs-patterns to shared team environments
  • Use solidjs-patterns for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: solidjs-patterns
description: SolidJS reactivity + UI state patterns for OpenWork
---

## Why this skill exists

OpenWork’s UI is SolidJS: it updates via **signals**, not React-style rerenders.
Most “UI stuck” bugs are actually **state coupling** bugs (e.g. one global `busy()` disabling an unrelated action), not rerender issues.

This skill captures the patterns we want to consistently use in OpenWork.

## Core rules

- Prefer **fine-grained signals** over shared global flags.
- Keep async actions **scoped** (each action gets its own `pending` state).
- Derive UI state via `createMemo()` instead of duplicating booleans.
- Avoid mutating arrays/objects stored in signals; always create new values.

## Scoped async actions (recommended)

When an operation can overlap with others (permissions, installs, background refresh), don’t reuse a global `busy()`.

Use a dedicated signal per action:

```ts
const [replying, setReplying] = createSignal(false);

async function respond() {
  if (replying()) return;
  setReplying(true);
  try {
    await doTheThing();
  } finally {
    setReplying(false);
  }
}
```

### Why

A single `busy()` boolean creates deadlocks:

- Long-running task sets `busy(true)`
- A permission prompt appears and its buttons are disabled by `busy()`
- The task can’t continue until permission is answered
- The user can’t answer because buttons are disabled

Fix: permission UI must be disabled only by a **permission-specific** pending state.

## Signal snapshots in async handlers

If you read signals inside an async function and you need stable values, snapshot early:

```ts
const request = activePermission();
if (!request) return;
const requestID = request.id;

await respondPermission(requestID, "always");
```

## Derived UI state

Prefer `createMemo()` for computed disabled states:

```ts
const canSend = createMemo(() => prompt().trim().length > 0 && !busy());
```

## Lists

- Use setter callbacks for derived updates:

```ts
setItems((current) => current.filter((x) => x.id !== id));
```

- Don’t mutate `current` in-place.

## Practical checklist (SolidJS UI changes)

- Does any button depend on a global flag that could be true during long-running work?
- Could two async actions overlap and fight over one boolean?
- Is any UI state duplicated (can be derived instead)?
- Do event handlers read signals after an `await` where values might have changed?

## References

- SolidJS: https://www.solidjs.com/docs/latest
- SolidJS signals: https://www.solidjs.com/docs/latest/api#createsignal
- SolidJS memos: https://www.solidjs.com/docs/latest/api#creatememo
solidjs-patterns | SkillHub