solidjs — Cursor rule: what it does, how to install
A Cursor rule for SolidJS 1.x covering reactivity, component structure, state, effects, and cleanup in JavaScript and JSX files.
.cursor/rules/solidjs.mdcWhat solidjs does
This rule guides SolidJS 1.x work in files matching **/*.{js,jsx}. It keeps component props reactive by avoiding top-level destructuring, using mergeProps for defaults, and applying splitProps when known and rest props must be separated. Local primitive state uses createSignal; nested or shared objects use createStore.
The guidance puts side effects inside createEffect and resource disposal inside onCleanup, including timers, subscriptions, and event listeners. It also recommends small components, PascalCase filenames, and Vite CSS Modules for local styles. The scope is SolidJS 1.x: SolidJS 2.0 is described as experimental, so this rule should not be used as guidance for its APIs.
What it helps with
- preserve reactive component props
- choose state primitives for local and nested data
- place side effects inside
createEffect - dispose of timers and subscriptions with
onCleanup - separate declared and pass-through props with
splitProps
Example prompts for the agent
- Review this SolidJS component and remove top-level props destructuring.
- Use
createSignalfor local state andcreateStorefor nested data. - Find side effects in
*.jsxfiles and add cleanup withonCleanup.
How to install solidjs
Manually: put the files in place
.cursor/rules/solidjs.mdcFrontmatter: description, globs, alwaysApply
Manually: put the files in place
.claude/rules/solidjs.mdThe paths frontmatter field limits the files: move globs from the source into paths
AGENTS.md
Codex reads AGENTS.md: paste the rule text there
Manually: put the files in place
.github/instructions/solidjs.instructions.mdThe applyTo field sets which files it applies to: move globs from the source into applyTo
Manually: put the files in place
.devin/rules/solidjs.mdManually: put the files in place
.clinerules/solidjs.mdStep by step, with commands for each platform: Cursor rules: .mdc files, four modes and what replaced .cursorrules
Questions about solidjs
How do I install solidjs in Cursor?
Add the rule file at .cursor/rules/solidjs.mdc in your Cursor project.
What does the solidjs rule do?
It sets SolidJS 1.x guidance for reactive props, signals, stores, effects, cleanup, and component organization.
Which files does solidjs cover?
The rule applies to JavaScript and JSX files matching **/*.{js,jsx}.
Source text
solidjs.mdc · CC0-1.0
---
description: This guide provides definitive, opinionated best practices for writing high-performance, maintainable SolidJS applications, focusing on reactivity, component architecture, and common pitfalls.
globs: **/*.{js,jsx}
---
# solidjs Best Practices
This document outlines the definitive best practices for developing with SolidJS 1.x. Adhere to these guidelines to leverage Solid's fine-grained reactivity, ensure optimal performance, and maintain a consistent, scalable codebase.
---
## 1. Use SolidJS 1.x (Stable)
**Always use the current stable 1.x release.** SolidJS 2.0 is experimental and not ready for production. Avoid any features or APIs mentioned for 2.0.
## 2. Component Architecture & Code Organization
### 2.1. Component File Naming
**Use PascalCase for component filenames.** This clearly distinguishes components from other modules.
* ❌ BAD: `mybutton.jsx`, `user-profile.jsx`
* ✅ GOOD: `MyButton.jsx`, `UserProfile.jsx`
### 2.2. Keep Components Lean
**Components should be small and focused.** Extract complex logic or UI parts into separate components or custom primitives.
### 2.3. Colocate Styles
**Use Vite's CSS Modules for component-specific styling.** This provides scoped styles without runtime overhead.
* ❌ BAD: Global CSS files, CSS-in-JS libraries with runtime.
* ✅ GOOD:
```jsx
// MyComponent.module.css
.container {
background-color: var(--color-primary);
}
.text {
color: white;
}
// MyComponent.jsx
import styles from './MyComponent.module.css';
function MyComponent() {
return <div class={styles.container}><span class={styles.text}>Hello</span></div>;
}
```
## 3. Props Handling
SolidJS props are reactive getters. Incorrect handling breaks reactivity.
### 3.1. Never Destructure Props Directly
**Do not destructure `props` at the component's top level.** This immediately loses reactivity. Access props via `props.propertyName`.
* ❌ BAD:
```jsx
function MyComponent({ name, age }) { // React pattern, breaks Solid reactivity
return <div>{name} is {age}</div>;
}
```
* ✅ GOOD:
```jsx
function MyComponent(props) {
return <div>{props.name} is {props.age}</div>; // Access directly
}
```
### 3.2. Apply Default Props with `mergeProps`
**Use `mergeProps` for default props.** This preserves reactivity and merges objects non-destructively.
* ❌ BAD:
```jsx
function MyComponent(props) {
const name = props.name || "Guest"; // Loses reactivity if props.name is a signal
return <div>Hello, {name}</div>;
}
```
* ✅ GOOD:
```jsx
import { mergeProps } from 'solid-js';
function MyComponent(props) {
const merged = mergeProps({ name: "Guest", greeting: "Hello" }, props);
return <div>{merged.greeting}, {merged.name}!</div>;
}
```
### 3.3. Use `splitProps` for Spreading
**When spreading props, use `splitProps` to separate known props from rest props.** This is crucial for accessibility and avoiding prop conflicts.
* ❌ BAD:
```jsx
function MyInput(props) {
return <input type="text" {...props} />; // Unsafe, can overwrite internal props
}
```
* ✅ GOOD:
```jsx
import { splitProps } from 'solid-js';
function MyInput(props) {
const [local, rest] = splitProps(props, ["label", "onChange"]);
return (
<label>
{local.label}
<input type="text" onChange={local.onChange} {...rest} />
</label>
);
}
```
## 4. State Management
### 4.1. Signals for Local State
**Use `createSignal` for simple, primitive, or local component state.** It's the most performant and idiomatic way to manage reactive values.
* ❌ BAD: `let count = 0;` (non-reactive)
* ✅ GOOD:
```jsx
import { createSignal } from 'solid-js';
function Counter() {
const [count, setCount] = createSignal(0);
return <button onClick={() => setCount(c => c + 1)}>{count()}</button>;
}
```
### 4.2. Stores for Complex/Global State
**Use `createStore` for nested, mutable objects or global state.** Stores provide deep reactivity for objects.
* ❌ BAD: `createSignal({ user: { name: "John" } })` (nested updates are not reactive without manual spreading)
* ✅ GOOD:
```jsx
import { createStore } from 'solid-js/store';
const [user, setUser] = createStore({ firstName: "John", lastName: "Doe" });
function UserProfile() {
return (
<div>
<p>Name: {user.firstName} {user.lastName}</p>
<button onClick={() => setUser("firstName", "Jane")}>Change Name</button>
</div>
);
}
```
## 5. Side Effects & Lifecycle
### 5.1. `createEffect` for Side Effects
**Encapsulate all side effects in `createEffect`.** Solid automatically tracks dependencies, ensuring effects run only when necessary.
* ❌ BAD: `console.log(mySignal());` outside `createEffect` (runs once)
* ✅ GOOD:
```jsx
import { createSignal, createEffect } from 'solid-js';
function Logger() {
const [value, setValue] = createSignal("initial");
createEffect(() => {
console.log("Value changed:", value()); // Runs on initial render and whenever value() changes
});
return <input onInput={(e) => setValue(e.target.value)} value={value()} />;
}
```
### 5.2. `onCleanup` for Resource Management
**Use `onCleanup` to dispose of resources (subscriptions, timers, event listeners).** It runs when the reactive scope (component, effect) is destroyed.
* ❌ BAD: Global `clearInterval` or `removeEventListener` without `onCleanup`.
* ✅ GOOD:
```jsx
import { createEffect, onCleanup } from 'solid-js';
function Timer() {
createEffect(() => {
const interval = setInterval(() => console.log("tick"), 1000);
onCleanup(() => clearInterval(interval)); // Cleans up when component/effect unmounts
});
return <div>Timer running...</div>;
}
```
## 6. Performance Considerations
### 6.1. Avoid Unnecessary Re-renders
Solid's fine-grained reactivity minimizes re-renders, but be mindful of creating new functions or objects inside JSX that aren't memoized.
* ❌ BAD:
```jsx
<MyComponent data={{ id: 1 }} /> // Creates new object on every parent update
```
* ✅ GOOD:
```jsx
const data = { id: 1 };
<MyComponent data={data} /> // Object reference remains stable
```
### 6.2. Lazy Loading
**Use dynamic imports for route-level components.** This reduces initial bundle size.
* ✅ GOOD:
```jsx
import { lazy } from 'solid-js';
import { Routes, Route } from '@solidjs/router';
const HomePage = lazy(() => import('./pages/Home'));
const AboutPage = lazy(() => import('./pages/About'));
function AppRoutes() {
return (
<Routes>
<Route path="/" component={HomePage} />
<Route path="/about" component={AboutPage} />
</Routes>
);
}
```
## 7. Ecosystem Tools
**Leverage official and community-vetted tools.**
* **Bundling**: `vite-plugin-solid`
* **Routing**: `solid-router` (or SolidStart)
* **Head Management**: `solid-meta`
* **Linting**: `eslint-plugin-solid`
* **Testing**: `solid-testing-library`
## 8. Accessibility
**Prioritize semantic HTML and WAI-ARIA attributes.** SolidJS does not abstract away the DOM, making direct accessibility implementation straightforward.
* ✅ GOOD:
```jsx
<button aria-label="Close dialog" onClick={closeDialog}>X</button>
<input type="checkbox" id="agree" checked={agreed()} onChange={toggleAgreed} />
<label for="agree">I agree to terms</label>
```
## 9. Testing Approaches
**Use `solid-testing-library` for unit and integration tests.** It provides a user-centric API similar to React Testing Library.
* ✅ GOOD:
```jsx
import { render, screen } from 'solid-testing-library';
import { createSignal } from 'solid-js';
import MyComponent from './MyComponent';
test('MyComponent displays the correct count', async () => {
const [count, setCount] = createSignal(0);
render(() => <MyComponent count={count()} />);
expect(screen.getByText(/Count: 0/i)).toBeInTheDocument();
setCount(1);
await Promise.resolve(); // Wait for Solid's microtask queue
expect(screen.getByText(/Count: 1/i)).toBeInTheDocument();
});
```
© sanjeed5 · CC0-1.0 · sanjeed5/awesome-cursor-rules-mdc