> solid
SolidJS is a reactive UI library that compiles to efficient vanilla JavaScript. It uses fine-grained reactivity with signals and stores, has no virtual DOM, and provides JSX components with excellent performance and small bundle size.
curl "https://skillshub.wtf/TerminalSkills/skills/solid?format=md"SolidJS
SolidJS uses fine-grained reactivity with signals — no virtual DOM diffing. Components run once, and only the specific DOM nodes that depend on changed signals update. This makes it extremely fast.
Installation
# Create SolidJS project
npx degit solidjs/templates/ts my-app
cd my-app
npm install
npm run dev
Project Structure
# SolidJS project layout
src/
├── index.tsx # Entry point
├── App.tsx # Root component
├── routes/ # Page components
│ ├── Home.tsx
│ └── Articles.tsx
├── components/ # Shared components
│ └── ArticleCard.tsx
├── stores/ # Stores for state
│ └── articles.ts
├── lib/ # Utilities
│ └── api.ts
└── index.css
Signals (Primitives)
// src/components/Counter.tsx — basic signals demo
import { createSignal, createEffect, createMemo } from 'solid-js';
export default function Counter() {
const [count, setCount] = createSignal(0);
const doubled = createMemo(() => count() * 2);
createEffect(() => {
console.log(`Count is now: ${count()}`);
});
return (
<div>
<p>Count: {count()} (doubled: {doubled()})</p>
<button onClick={() => setCount((c) => c + 1)}>+1</button>
</div>
);
}
Components and Props
// src/components/ArticleCard.tsx — component with typed props
import { Component } from 'solid-js';
interface Article {
id: number;
title: string;
slug: string;
excerpt: string;
}
interface Props {
article: Article;
onDelete?: (id: number) => void;
}
const ArticleCard: Component<Props> = (props) => {
return (
<article>
<a href={`/articles/${props.article.slug}`}>
<h2>{props.article.title}</h2>
</a>
<p>{props.article.excerpt}</p>
<button onClick={() => props.onDelete?.(props.article.id)}>Delete</button>
</article>
);
};
export default ArticleCard;
Resources (Data Fetching)
// src/routes/Articles.tsx — async data fetching with createResource
import { createResource, For, Show, Suspense } from 'solid-js';
import ArticleCard from '../components/ArticleCard';
async function fetchArticles(): Promise<Article[]> {
const res = await fetch('/api/articles');
return res.json();
}
export default function Articles() {
const [articles] = createResource(fetchArticles);
return (
<div>
<h1>Articles</h1>
<Suspense fallback={<p>Loading...</p>}>
<Show when={!articles.error} fallback={<p>Error loading articles.</p>}>
<For each={articles()}>
{(article) => <ArticleCard article={article} />}
</For>
</Show>
</Suspense>
</div>
);
}
Stores (Complex State)
// src/stores/articles.ts — store for nested reactive state
import { createStore, produce } from 'solid-js/store';
interface ArticlesState {
items: Article[];
loading: boolean;
filter: string;
}
const [state, setState] = createStore<ArticlesState>({
items: [],
loading: false,
filter: '',
});
export function useArticles() {
async function fetchAll() {
setState('loading', true);
const res = await fetch('/api/articles');
const data = await res.json();
setState({ items: data, loading: false });
}
function removeArticle(id: number) {
setState('items', (items) => items.filter((a) => a.id !== id));
}
function setFilter(query: string) {
setState('filter', query);
}
return { state, fetchAll, removeArticle, setFilter };
}
Control Flow
// src/components/ArticleList.tsx — control flow components
import { For, Show, Switch, Match } from 'solid-js';
export default function ArticleList(props: { articles: Article[]; status: string }) {
return (
<div>
<Switch>
<Match when={props.status === 'loading'}>
<p>Loading...</p>
</Match>
<Match when={props.status === 'error'}>
<p>Error loading articles.</p>
</Match>
<Match when={props.status === 'ready'}>
<Show when={props.articles.length > 0} fallback={<p>No articles.</p>}>
<For each={props.articles}>
{(article) => <ArticleCard article={article} />}
</For>
</Show>
</Match>
</Switch>
</div>
);
}
Routing (SolidStart)
// src/routes/articles/[slug].tsx — SolidStart file-based route
import { useParams } from '@solidjs/router';
import { createResource } from 'solid-js';
export default function ArticlePage() {
const params = useParams();
const [article] = createResource(() => params.slug, async (slug) => {
const res = await fetch(`/api/articles/${slug}`);
if (!res.ok) throw new Error('Not found');
return res.json();
});
return (
<Suspense fallback={<p>Loading...</p>}>
<Show when={article()}>
{(a) => (
<article>
<h1>{a().title}</h1>
<div innerHTML={a().body} />
</article>
)}
</Show>
</Suspense>
);
}
Context (Dependency Injection)
// src/lib/AuthContext.tsx — context for shared auth state
import { createContext, useContext, ParentComponent } from 'solid-js';
import { createStore } from 'solid-js/store';
const AuthContext = createContext<{ user: () => User | null; login: (u: User) => void }>();
export const AuthProvider: ParentComponent = (props) => {
const [state, setState] = createStore<{ user: User | null }>({ user: null });
const value = {
user: () => state.user,
login: (u: User) => setState('user', u),
};
return <AuthContext.Provider value={value}>{props.children}</AuthContext.Provider>;
};
export function useAuth() {
return useContext(AuthContext)!;
}
Key Patterns
- Signals are called as functions:
count()reads,setCount()writes — parentheses matter - Components run once; only signal-dependent expressions re-execute
- Use
<For>for lists (keyed by reference),<Index>for index-based iteration - Use
<Show>for conditional rendering,<Switch>/<Match>for multiple branches - Use
createResourcefor async data — it integrates with<Suspense> - Use stores (
createStore) for nested objects — signals are for primitives - Don't destructure props — it breaks reactivity. Access
props.xdirectly
> related_skills --same-repo
> zustand
You are an expert in Zustand, the small, fast, and scalable state management library for React. You help developers manage global state without boilerplate using Zustand's hook-based stores, selectors for performance, middleware (persist, devtools, immer), computed values, and async actions — replacing Redux complexity with a simple, un-opinionated API in under 1KB.
> zoho
Integrate and automate Zoho products. Use when a user asks to work with Zoho CRM, Zoho Books, Zoho Desk, Zoho Projects, Zoho Mail, or Zoho Creator, build custom integrations via Zoho APIs, automate workflows with Deluge scripting, sync data between Zoho apps and external systems, manage leads and deals, automate invoicing, build custom Zoho Creator apps, set up webhooks, or manage Zoho organization settings. Covers Zoho CRM, Books, Desk, Projects, Creator, and cross-product integrations.
> zod
You are an expert in Zod, the TypeScript-first schema declaration and validation library. You help developers define schemas that validate data at runtime AND infer TypeScript types at compile time — eliminating the need to write types and validators separately. Used for API input validation, form validation, environment variables, config files, and any data boundary.
> zipkin
Deploy and configure Zipkin for distributed tracing and request flow visualization. Use when a user needs to set up trace collection, instrument Java/Spring or other services with Zipkin, analyze service dependencies, or configure storage backends for trace data.