Component signatures
Destructure props in the parameter
Props interface naming
Name the interfaceComponentNameProps. Use the on prefix for callback props.
Don’t annotate return types
Let TypeScript infer component return types. The JSX factory maps tag names to specific element types — an explicit: HTMLElement annotation is a lossy upcast.
Reactivity
let for local state
Use let for local state. The compiler transforms it into a signal automatically.
const for derived values
Use const for values derived from state. The compiler wraps it in computed() automatically.
JSX
Fully declarative
All UI code must be declarative. NoappendChild, innerHTML, textContent assignment, setAttribute, or document.createElement.
Use JSX for components, not function calls
Conditionals with && and ternary
Lists with .map() and key
Styling
css() for scoped styles
variants() for parameterized styles
Inline style only for dynamic values
Use css() tokens for anything theme-related. Reserve inline styles for one-off layout values like margins, transforms, or dynamic positioning.
Data fetching
query() is auto-disposed
Don’t manually manage query lifecycle — queries auto-register cleanup with the component scope. When the component unmounts, the query stops reactive effects and timers automatically.
Access query properties directly
Query properties like.data, .loading, and .error work directly in both JSX and event handlers — no unwrapping needed.
Context
Create a convenience hook
Always create a typeduse* accessor that throws on missing provider.