solidjs
Builds UIs with SolidJS including signals, effects, memos, and fine-grained reactivity. Use when creating high-performance reactive applications, building without virtual DOM, or needing granular updates.
Best use case
solidjs is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Builds UIs with SolidJS including signals, effects, memos, and fine-grained reactivity. Use when creating high-performance reactive applications, building without virtual DOM, or needing granular updates.
Teams using solidjs should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/solidjs/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How solidjs Compares
| Feature / Agent | solidjs | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Builds UIs with SolidJS including signals, effects, memos, and fine-grained reactivity. Use when creating high-performance reactive applications, building without virtual DOM, or needing granular updates.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# SolidJS
A declarative JavaScript library for building UIs with fine-grained reactivity.
## Quick Start
**Create project:**
```bash
npx degit solidjs/templates/ts my-app
cd my-app
npm install
npm run dev
```
## Signals
### Basic Signal
```tsx
import { createSignal } from 'solid-js';
function Counter() {
const [count, setCount] = createSignal(0);
return (
<button onClick={() => setCount(count() + 1)}>
Count: {count()}
</button>
);
}
```
### Signal Patterns
```tsx
import { createSignal } from 'solid-js';
function App() {
// Primitive signal
const [name, setName] = createSignal('');
// Object signal
const [user, setUser] = createSignal({ name: 'John', age: 30 });
// Update primitives
setName('Jane');
// Update objects (replace entire object)
setUser({ ...user(), age: 31 });
// Functional update
setCount(prev => prev + 1);
return (
<div>
<p>Name: {name()}</p>
<p>User: {user().name}</p>
</div>
);
}
```
## Effects
### createEffect
```tsx
import { createSignal, createEffect } from 'solid-js';
function Logger() {
const [count, setCount] = createSignal(0);
// Runs on initial render and when count changes
createEffect(() => {
console.log('Count changed:', count());
});
// With cleanup
createEffect(() => {
const handler = () => console.log('clicked');
document.addEventListener('click', handler);
// Cleanup function
onCleanup(() => {
document.removeEventListener('click', handler);
});
});
return <button onClick={() => setCount(c => c + 1)}>Increment</button>;
}
```
### onMount and onCleanup
```tsx
import { onMount, onCleanup } from 'solid-js';
function Timer() {
const [time, setTime] = createSignal(0);
onMount(() => {
const interval = setInterval(() => {
setTime(t => t + 1);
}, 1000);
onCleanup(() => clearInterval(interval));
});
return <p>Time: {time()}s</p>;
}
```
## Memos (Derived State)
```tsx
import { createSignal, createMemo } from 'solid-js';
function App() {
const [count, setCount] = createSignal(0);
const [multiplier, setMultiplier] = createSignal(2);
// Computed value - only recalculates when dependencies change
const doubled = createMemo(() => count() * multiplier());
// Expensive computation
const filtered = createMemo(() => {
console.log('Computing filtered list...');
return items().filter(item => item.active);
});
return (
<div>
<p>Count: {count()}</p>
<p>Doubled: {doubled()}</p>
</div>
);
}
```
## Components
### Basic Component
```tsx
import { Component } from 'solid-js';
interface Props {
name: string;
age?: number;
}
const Greeting: Component<Props> = (props) => {
return (
<div>
<h1>Hello, {props.name}!</h1>
{props.age && <p>Age: {props.age}</p>}
</div>
);
};
// Usage
<Greeting name="John" age={30} />
```
### Props with Defaults
```tsx
import { mergeProps } from 'solid-js';
interface Props {
count?: number;
label?: string;
}
function Counter(props: Props) {
const merged = mergeProps({ count: 0, label: 'Count' }, props);
return (
<p>{merged.label}: {merged.count}</p>
);
}
```
### Splitting Props
```tsx
import { splitProps } from 'solid-js';
interface Props {
name: string;
class?: string;
style?: string;
}
function Button(props: Props) {
const [local, others] = splitProps(props, ['name']);
return (
<button {...others}>
{local.name}
</button>
);
}
```
## Children
```tsx
import { ParentComponent, children } from 'solid-js';
const Card: ParentComponent<{ title: string }> = (props) => {
return (
<div class="card">
<h2>{props.title}</h2>
<div class="content">
{props.children}
</div>
</div>
);
};
// With resolved children
const List: ParentComponent = (props) => {
const resolved = children(() => props.children);
createEffect(() => {
console.log('Children:', resolved());
});
return <ul>{resolved()}</ul>;
};
```
## Control Flow
### Show
```tsx
import { Show } from 'solid-js';
function App() {
const [loggedIn, setLoggedIn] = createSignal(false);
return (
<Show
when={loggedIn()}
fallback={<button onClick={() => setLoggedIn(true)}>Log in</button>}
>
<button onClick={() => setLoggedIn(false)}>Log out</button>
</Show>
);
}
```
### For
```tsx
import { For } from 'solid-js';
function TodoList() {
const [todos, setTodos] = createSignal([
{ id: 1, text: 'Learn Solid' },
{ id: 2, text: 'Build app' },
]);
return (
<ul>
<For each={todos()}>
{(todo, index) => (
<li>
{index() + 1}. {todo.text}
</li>
)}
</For>
</ul>
);
}
```
### Index
```tsx
import { Index } from 'solid-js';
// For non-keyed lists where items may change but indices stay stable
function Grid() {
const [cells, setCells] = createSignal(['A', 'B', 'C']);
return (
<div>
<Index each={cells()}>
{(cell, index) => (
<div>{index}: {cell()}</div>
)}
</Index>
</div>
);
}
```
### Switch/Match
```tsx
import { Switch, Match } from 'solid-js';
function StatusMessage() {
const [status, setStatus] = createSignal('loading');
return (
<Switch fallback={<p>Unknown status</p>}>
<Match when={status() === 'loading'}>
<p>Loading...</p>
</Match>
<Match when={status() === 'success'}>
<p>Success!</p>
</Match>
<Match when={status() === 'error'}>
<p>Error occurred</p>
</Match>
</Switch>
);
}
```
### Dynamic
```tsx
import { Dynamic } from 'solid-js/web';
function App() {
const [component, setComponent] = createSignal('div');
return (
<Dynamic component={component()} class="container">
Content
</Dynamic>
);
}
```
## Stores (Complex State)
```tsx
import { createStore, produce } from 'solid-js/store';
interface Todo {
id: number;
text: string;
completed: boolean;
}
function TodoApp() {
const [todos, setTodos] = createStore<Todo[]>([]);
const addTodo = (text: string) => {
setTodos(todos.length, {
id: Date.now(),
text,
completed: false,
});
};
const toggleTodo = (id: number) => {
setTodos(
todo => todo.id === id,
'completed',
completed => !completed
);
};
// Using produce for complex updates
const removeTodo = (id: number) => {
setTodos(produce(todos => {
const index = todos.findIndex(t => t.id === id);
if (index !== -1) todos.splice(index, 1);
}));
};
return (
<For each={todos}>
{todo => (
<div>
<span style={{ 'text-decoration': todo.completed ? 'line-through' : 'none' }}>
{todo.text}
</span>
<button onClick={() => toggleTodo(todo.id)}>Toggle</button>
</div>
)}
</For>
);
}
```
## Context
```tsx
import { createContext, useContext, ParentComponent } from 'solid-js';
interface ThemeContext {
theme: () => string;
setTheme: (theme: string) => void;
}
const ThemeContext = createContext<ThemeContext>();
const ThemeProvider: ParentComponent = (props) => {
const [theme, setTheme] = createSignal('light');
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{props.children}
</ThemeContext.Provider>
);
};
function useTheme() {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme must be used within ThemeProvider');
}
return context;
}
function ThemedButton() {
const { theme, setTheme } = useTheme();
return (
<button onClick={() => setTheme(theme() === 'light' ? 'dark' : 'light')}>
Theme: {theme()}
</button>
);
}
```
## Resources (Async Data)
```tsx
import { createResource, Suspense, ErrorBoundary } from 'solid-js';
async function fetchUser(id: string) {
const res = await fetch(`/api/users/${id}`);
return res.json();
}
function UserProfile() {
const [userId, setUserId] = createSignal('1');
const [user, { refetch, mutate }] = createResource(userId, fetchUser);
return (
<ErrorBoundary fallback={<p>Error loading user</p>}>
<Suspense fallback={<p>Loading...</p>}>
<Show when={user()}>
<div>
<h1>{user().name}</h1>
<button onClick={refetch}>Refresh</button>
</div>
</Show>
</Suspense>
</ErrorBoundary>
);
}
```
## Refs
```tsx
function TextInput() {
let inputRef: HTMLInputElement | undefined;
onMount(() => {
inputRef?.focus();
});
return <input ref={inputRef} />;
}
// Callback ref
function CallbackRef() {
return (
<input ref={(el) => {
// Called when element is created
el.focus();
}} />
);
}
```
## Directives
```tsx
// Define directive
function clickOutside(el: Element, accessor: () => () => void) {
const onClick = (e: MouseEvent) => {
if (!el.contains(e.target as Node)) {
accessor()?.();
}
};
document.addEventListener('click', onClick);
onCleanup(() => document.removeEventListener('click', onClick));
}
// Use directive
function Dropdown() {
const [open, setOpen] = createSignal(false);
return (
<div use:clickOutside={() => setOpen(false)}>
<button onClick={() => setOpen(true)}>Open</button>
<Show when={open()}>
<div>Dropdown content</div>
</Show>
</div>
);
}
```
## Best Practices
1. **Call signals as functions** - Always use `count()` not `count`
2. **Use For for keyed lists** - More efficient than map
3. **Use stores for complex state** - Nested reactivity
4. **Avoid destructuring props** - Breaks reactivity
5. **Use createMemo for expensive computations** - Caches results
## Common Mistakes
| Mistake | Fix |
|---------|-----|
| Destructuring props | Access props.x directly |
| Forgetting to call signal | Use count() not count |
| Using map instead of For | Use For component |
| Mutating signal objects | Replace entire object |
| Missing Suspense for resources | Wrap in Suspense |
## Reference Files
- [references/reactivity.md](references/reactivity.md) - Reactivity deep dive
- [references/stores.md](references/stores.md) - Store patterns
- [references/router.md](references/router.md) - Solid RouterRelated Skills
bgo
Automates the complete Blender build-go workflow, from building and packaging your extension/add-on to removing old versions, installing, enabling, and launching Blender for quick testing and iteration.
ssh-server-admin
Securely connect to and manage remote Linux/Unix servers via SSH. Execute commands, transfer files (SCP/SFTP), set up port forwarding and tunnels. Use when the user asks to SSH into a server, connect to a remote machine, run remote commands, upload/download files to servers, set up tunnels, or perform server administration tasks. Works on Windows, macOS, and Linux.
sqlmodel-task-models
This skill should be used when defining a robust, type-safe, and async-compatible database schema for the Todo application using SQLModel, ensuring compatibility with Better Auth and optimized for PostgreSQL.
sql-server-dba-dev-expert
Use when designing, implementing, optimizing, or troubleshooting AF.ECT.Database schemas, queries, stored procedures, performance tuning, data integrity, or operational database tasks while following Microsoft best practices
sql-pro
Master modern SQL with cloud-native databases, OLTP/OLAP optimization, and advanced query techniques. Expert in performance tuning, data modeling, and hybrid analytical systems. Use PROACTIVELY for database optimization or complex analysis.
sql
Guide for working with SQL queries, in particular for SQLite. Use this skill when writing SQL queries, analyzing database schemas, designing migrations, or working with SQLite-related code.
sql-databases
SQL query optimization, schema design, indexing strategies, and relational database mastery for production data systems
sql-and-database
SQL writing and database engineering patterns, standards, and procedures. Use for designing database schemas, writing performant SQL queries, normalisation strategies, indexing, joins optimisation, locking mechanics, transactions, query debugging with EXPLAIN, and ORM integration. Applies to PostgreSQL, MySQL, MariaDB, SQL Server, and Oracle. Covers ORM usage with TypeORM, Prisma, Doctrine, Eloquent, Entity Framework, Hibernate, and GORM.
springboot-architecture-analyzer
系統化分析 Spring Boot 專案並生成完整的企業級架構文件,涵蓋系統概述、架構視圖、技術細節、部署策略等所有關鍵面向。
springboot-4-migration
Comprehensive guide for migrating Spring Boot applications from 3.x to 4.0, focusing on Gradle Kotlin DSL and version catalogs Triggers on: **/*.java, **/*.kt, **/build.gradle.kts, **/build.gradle, **/settings.gradle.kts, **/gradle/libs.versions.toml, **/*.properties, **/*.yml, **/*.yaml
spring-rest-api
RESTful API design with Spring Boot including OpenAPI/Swagger documentation, content negotiation, CORS, pagination, HATEOAS, and API versioning patterns.
spring-reactive
Build reactive applications - WebFlux, Mono/Flux, R2DBC, backpressure, reactive streams