Solid.js / SolidStart Code Generation Rules
Loaded when: package.json contains solid-js or solid-start.
These rules are ADDITIVE to the universal rules in SKILL.md.
Project conventions override: If design-tokens.json contains a conventions section, those conventions take priority over the canonical component template and patterns in this file for stylistic decisions (declaration style, export style, type definitions, file naming, import ordering, props pattern). This file remains authoritative for framework-specific syntax requirements (createSignal, createResource, class, no props destructuring at call site).
0. NON-NEGOTIABLES
These Solid.js / SolidStart rules hold for every generated file. No exceptions.
- NEVER destructure props in the component signature or body. Solid's reactivity is fine-grained — destructuring breaks it. MUST access props via
props.xxx. UsesplitPropsfor safe forwarding andmergePropsfor reactive defaults. - MUST call signals as functions. Write
count()inside JSX and reactive contexts, NEVER barecount. Bare references read the getter function itself, not the value. - MUST use
<For>and<Show>components for control flow. NEVER use.map()or conditional ternaries directly in JSX — they do not preserve DOM nodes across updates. - NEVER use React hooks (
useState,useEffect,useMemo). Solid has no React hooks. UsecreateSignal,createEffect,createMemo,createResource. - MUST use
class, NEVERclassName. Solid supports both butclassis the documented convention in modern Solid.
1. KEY REMINDERS
- NEVER destructure props -- it breaks reactivity. Always use
props.title, not{ title }. - Signals are called as functions:
count()notcount. - Use
classnotclassName. UseonInputnotonChangefor live text input. - Use
<For>/<Show>components, NEVER.map()or ternaries in JSX (they don't preserve DOM nodes). - NEVER use
createEffect+ setter to derive state -- usecreateMemoinstead. - Use
splitPropsfor safe prop forwarding,mergePropsfor reactive defaults.
2. SYNTAX QUICK REFERENCE (framework-specific gotchas and newer APIs only)
| Concept | Solid.js Syntax |
|---|---|
| Split props | const [local, rest] = splitProps(props, ["class", "onClick"]) -- safe prop forwarding |
| Merge props | const merged = mergeProps({ size: "md" }, props) -- reactive default values |
| Refs | let ref!: HTMLDivElement; then ref={ref} |
Critical differences from React: signals called as functions (count()), class not className, onInput not onChange, <For>/<Show> not .map()/ternaries.
3. FILE STRUCTURE CONVENTIONS
| Type | Path |
|---|---|
| Page (SolidStart) | src/routes/index.tsx, src/routes/about.tsx |
| Nested route | src/routes/dashboard/settings.tsx |
| Dynamic route | src/routes/users/[id].tsx |
| Layout | src/routes/(layout).tsx |
| Reusable component | src/components/ComponentName.tsx |
| Lib / utils | src/lib/ or src/utils/ |
| API route | src/routes/api/endpoint.ts |
4. DATA FETCHING PATTERNS
| Context | Pattern |
|---|---|
| Client resource | const [data] = createResource(fetcher) |
| SolidStart server data | const getItems = query(async () => { "use server"; return db.items() }, "items") |
| Consume async | const data = createAsync(() => getItems()) from @solidjs/router |
| TanStack Query | createQuery(() => ({ queryKey, queryFn })) |
Default: createResource for client-only. SolidStart: query + createAsync. NEVER use deprecated createServerData$ or cache.
5. CLIENT / SERVER BOUNDARIES
SolidStart is server-rendered by default. Key rules:
- Use
"use server"to mark functions that must only run on the server - There is NO
"use client"directive — components render on both sides by default - Server-only code:
"use server"at top of function or file - Actions:
const myAction = action(async (formData) => { "use server"; ... })— for form mutations - Isomorphic by default — code runs on server first, then hydrates on client
6. STYLING SYNTAX
| Method | Syntax |
|---|---|
| Tailwind | class="flex items-center gap-2 text-sm" |
| Conditional | classList={{ active: isActive(), disabled: isDisabled() }} |
Always use class, NEVER className. Use classList for conditional classes. CSS property names in style use kebab-case strings as keys.
7. FRAMEWORK-SPECIFIC LIBRARY CATEGORIES
| Category | Solid Libraries |
|---|---|
| data_fetching | @tanstack/solid-query, createResource (built-in) |
| forms | @modular-forms/solid, @felte/solid |
| icons | solid-icons, lucide-solid |
| component_library | @kobalte/core, @ark-ui/solid, corvu |
| animation | solid-transition-group, motion, gsap |
| state | createSignal / createStore (built-in) |
| router | @solidjs/router (built-in with SolidStart) |
| tables | @tanstack/solid-table |
| meta | @solidjs/meta |
Rule: check package.json before importing. If a library from this table is already installed, use it. Never add a second library for the same category.
Library Boundary Values (SVG Chart Libraries)
Some libraries accept color/style values as string props, not CSS classes or variables. SVG-based chart libraries (solid-chartjs, d3) require hex/rgb strings because the SVG renderer does not resolve CSS custom properties at the attribute level.
Pattern: Resolve CSS variables at runtime with createSignal + onMount.
import { createSignal, onMount } from 'solid-js'
function resolveTokenColor(tokenVar: string): string {
return getComputedStyle(document.documentElement)
.getPropertyValue(tokenVar)
.trim() || '#000000'
}
const [chartColors, setChartColors] = createSignal({ primary: '#000000' })
onMount(() => {
setChartColors({
primary: resolveTokenColor('--colors-primary'),
})
})
When runtime resolution is not feasible, hardcoding is acceptable but MUST include a comment linking the value to its token:
// Token: colors.primary (#2563EB) — hardcoded for SVG chart compatibility
<rect fill="#2563EB" />
These values are exempt from the Phase 5 hardcoded-values audit (bucket A) because the library API requires them.