A declarative JavaScript library for building user interfaces with fine-grained reactivity.
—
Core reactive system providing signals, effects, and memos for building reactive applications with automatic dependency tracking and fine-grained updates.
Create reactive state with getter and setter functions that automatically track dependencies and trigger updates.
/**
* Creates a reactive state with getter and setter functions
* @param value - Initial value for the signal
* @param options - Configuration options for the signal
* @returns Tuple of [getter, setter] functions
*/
function createSignal<T>(): Signal<T | undefined>;
function createSignal<T>(value: T, options?: SignalOptions<T>): Signal<T>;
interface SignalOptions<T> {
equals?: false | ((prev: T, next: T) => boolean);
name?: string;
internal?: boolean;
}Usage Examples:
import { createSignal } from "solid-js";
// Basic signal
const [count, setCount] = createSignal(0);
console.log(count()); // 0
setCount(5);
console.log(count()); // 5
// Signal with custom equality
const [user, setUser] = createSignal(
{ name: "John", age: 30 },
{ equals: (prev, next) => prev.name === next.name && prev.age === next.age }
);
// Functional updates
setCount(prev => prev + 1);
setUser(prev => ({ ...prev, age: prev.age + 1 }));Create reactive computations that run automatically when their dependencies change.
/**
* Creates a reactive computation that runs after render phase
* @param fn - Effect function that tracks dependencies
* @param value - Initial value for the effect
* @param options - Configuration options
*/
function createEffect<T>(fn: EffectFunction<T>, value?: T, options?: EffectOptions): void;
/**
* Creates a reactive computation during render phase
* @param fn - Effect function that tracks dependencies
* @param value - Initial value for the effect
* @param options - Configuration options
*/
function createRenderEffect<T>(fn: EffectFunction<T>, value?: T, options?: EffectOptions): void;
/**
* Creates a reactive computation that runs immediately before render
* @param fn - Effect function that tracks dependencies
* @param value - Initial value for the effect
* @param options - Configuration options
*/
function createComputed<T>(fn: EffectFunction<T>, value?: T, options?: EffectOptions): void;
type EffectFunction<Prev, Next extends Prev = Prev> = (v: Prev) => Next;
interface EffectOptions {
name?: string;
}Usage Examples:
import { createSignal, createEffect } from "solid-js";
const [count, setCount] = createSignal(0);
// Basic effect
createEffect(() => {
console.log("Count is:", count());
});
// Effect with previous value
createEffect((prev) => {
const current = count();
console.log(`Count changed from ${prev} to ${current}`);
return current;
}, count());
// Effect with cleanup
createEffect(() => {
const timer = setInterval(() => {
setCount(c => c + 1);
}, 1000);
onCleanup(() => clearInterval(timer));
});Create derived reactive values that are memoized and only recalculate when their dependencies change.
/**
* Creates a readonly derived reactive memoized signal
* @param fn - Memo function that computes the derived value
* @param value - Initial value for the memo
* @param options - Configuration options
* @returns Accessor function for the memoized value
*/
function createMemo<T>(fn: EffectFunction<T>, value?: T, options?: MemoOptions<T>): Accessor<T>;
interface MemoOptions<T> extends EffectOptions {
equals?: false | ((prev: T, next: T) => boolean);
}Usage Examples:
import { createSignal, createMemo } from "solid-js";
const [firstName, setFirstName] = createSignal("John");
const [lastName, setLastName] = createSignal("Doe");
// Basic memo
const fullName = createMemo(() => `${firstName()} ${lastName()}`);
// Memo with custom equality
const expensiveComputation = createMemo(
() => someExpensiveFunction(firstName(), lastName()),
undefined,
{ equals: (prev, next) => prev.id === next.id }
);
// Using memos in components
function UserProfile() {
const displayName = createMemo(() => {
const first = firstName();
const last = lastName();
return first && last ? `${first} ${last}` : first || last || "Anonymous";
});
return <div>Hello, {displayName()}!</div>;
}Create complex reactive patterns and manage reactive ownership.
/**
* Creates a reactive computation with flexible tracking
* @param onInvalidate - Function called when dependencies change
* @param options - Configuration options
* @returns Function to run reactive computations
*/
function createReaction(
onInvalidate: () => void,
options?: EffectOptions
): (fn: () => void) => void;
/**
* Creates a reactive computation that only runs when browser is idle
* @param source - Source accessor to watch
* @param options - Configuration options
* @returns Deferred accessor
*/
function createDeferred<T>(
source: Accessor<T>,
options?: DeferredOptions<T>
): Accessor<T>;
/**
* Creates a conditional signal for O(2) instead of O(n) operations
* @param source - Source accessor to watch
* @param fn - Equality function for comparison
* @param options - Configuration options
* @returns Function that checks if key matches current value
*/
function createSelector<T, U>(
source: Accessor<T>,
fn?: (a: U, b: T) => boolean,
options?: BaseOptions
): (key: U) => boolean;
interface DeferredOptions<T> {
timeoutMs?: number;
equals?: false | ((prev: T, next: T) => boolean);
}Control reactive execution and dependency tracking.
/**
* Batches reactive updates within the block
* @param fn - Function to run in batch
* @returns Return value of the function
*/
function batch<T>(fn: () => T): T;
/**
* Ignores tracking context inside its scope
* @param fn - Function to run without tracking
* @returns Return value of the function
*/
function untrack<T>(fn: () => T): T;
/**
* Makes dependencies of a computation explicit
* @param deps - Dependencies to track
* @param fn - Function to run when dependencies change
* @param options - Configuration options
* @returns Return value of the function
*/
function on<S, T>(
deps: Accessor<S> | Accessor<S>[],
fn: (input: S, prevInput?: S, prevValue?: T) => T,
options?: OnOptions
): EffectFunction<undefined, T>;
interface OnOptions {
defer?: boolean;
}Manage component lifecycle and cleanup in reactive computations.
/**
* Runs an effect only after initial render on mount
* @param fn - Function to run on mount
*/
function onMount(fn: () => void): void;
/**
* Runs an effect once before the reactive scope is disposed
* @param fn - Function to run on cleanup
* @returns The cleanup function
*/
function onCleanup<T extends () => any>(fn: T): T;
/**
* Runs an effect whenever an error is thrown within child scopes
* @param fn - Function to run with the caught error
* @param handler - Error handler function
* @returns Return value or undefined if error occurred
*/
function catchError<T>(
fn: () => T,
handler: (err: Error) => void
): T | undefined;Usage Examples:
import { createSignal, createEffect, onMount, onCleanup, batch } from "solid-js";
function Timer() {
const [time, setTime] = createSignal(0);
const [isRunning, setIsRunning] = createSignal(false);
onMount(() => {
console.log("Timer component mounted");
});
createEffect(() => {
if (isRunning()) {
const interval = setInterval(() => {
setTime(t => t + 1);
}, 1000);
onCleanup(() => {
clearInterval(interval);
console.log("Timer cleanup");
});
}
});
const reset = () => {
batch(() => {
setTime(0);
setIsRunning(false);
});
};
return (
<div>
<div>Time: {time()}s</div>
<button onClick={() => setIsRunning(!isRunning())}>
{isRunning() ? "Stop" : "Start"}
</button>
<button onClick={reset}>Reset</button>
</div>
);
}Enable integration with external reactive systems and custom scheduling.
/**
* Enables integration with external reactive systems
* @param factory - Factory function for external sources
* @param untrack - Function to untrack dependencies (defaults to provided untrack)
*/
function enableExternalSource(
factory: ExternalSourceFactory,
untrack?: <V>(fn: () => V) => V
): void;
/**
* Enables custom scheduling for updates
* @param scheduler - Custom scheduler function (defaults to requestCallback)
*/
function enableScheduling(scheduler?: (fn: () => void) => void): void;
type ExternalSourceFactory = <T>(
fn: (track: Accessor<T>) => void,
trigger: () => void
) => () => void;Create and manage reactive ownership contexts for proper cleanup and component isolation.
/**
* Creates a reactive root context for ownership management
* @param fn - Function to run in the root context, receives dispose function
* @param detachedOwner - Optional owner to detach from
* @returns Return value of the function
*/
function createRoot<T>(fn: (dispose: () => void) => T, detachedOwner?: Owner): T;
/**
* Gets the current reactive owner context
* @returns Current owner or null if none
*/
function getOwner(): Owner | null;
/**
* Runs a function within a specific owner context
* @param owner - Owner context to run within
* @param fn - Function to run
* @returns Return value of the function
*/
function runWithOwner<T>(owner: Owner | null, fn: () => T): T | undefined;
/**
* Resolves children in a reactive context
* @param fn - Function that returns children
* @returns Resolved children accessor
*/
function children(fn: () => any): ChildrenReturn;
type RootFunction<T> = (dispose: () => void) => T;
type ChildrenReturn = Accessor<ResolvedChildren> & { toArray: () => ResolvedJSXElement[] };Usage Examples:
import { createRoot, createSignal, createEffect, getOwner, runWithOwner } from "solid-js";
// Basic root usage
const dispose = createRoot((dispose) => {
const [count, setCount] = createSignal(0);
createEffect(() => {
console.log("Count:", count());
});
// Clean up when needed
setTimeout(() => dispose(), 5000);
return dispose;
});
// Owner management
function ParentComponent() {
const owner = getOwner();
const childComputation = () => {
// This will run in the parent's context
runWithOwner(owner, () => {
createEffect(() => {
console.log("Child effect in parent context");
});
});
};
return <div onClick={childComputation}>Click me</div>;
}Create and consume context for passing data through the component tree.
/**
* Creates a context for passing data through component tree
* @param defaultValue - Default value when no provider is found
* @param options - Optional configuration
* @returns Context object with id and Provider
*/
function createContext<T>(defaultValue?: T, options?: EffectOptions): Context<T>;
/**
* Consumes a context value from the nearest provider
* @param context - Context to consume
* @returns Current context value
*/
function useContext<T>(context: Context<T>): T;
interface Context<T> {
id: symbol;
Provider: ContextProviderComponent<T>;
defaultValue: T;
}
type ContextProviderComponent<T> = Component<{
value: T;
children: JSX.Element;
}>;Usage Examples:
import { createContext, useContext } from "solid-js";
// Create theme context
const ThemeContext = createContext("light");
function App() {
return (
<ThemeContext.Provider value="dark">
<UserInterface />
</ThemeContext.Provider>
);
}
function UserInterface() {
const theme = useContext(ThemeContext);
return (
<div class={theme === "dark" ? "dark-theme" : "light-theme"}>
Current theme: {theme}
</div>
);
}Handle asynchronous data loading with reactive resources.
/**
* Creates a resource for handling async data
* @param fetcher - Function to fetch the resource data
* @param options - Configuration options
* @returns Resource tuple [resource accessor, resource actions]
*/
function createResource<T, R = unknown>(
fetcher: ResourceFetcher<true, T, R>,
options?: ResourceOptions<T, true>
): ResourceReturn<T, R>;
/**
* Creates a resource with a source signal
* @param source - Source signal that triggers refetch
* @param fetcher - Function to fetch the resource data
* @param options - Configuration options
* @returns Resource tuple [resource accessor, resource actions]
*/
function createResource<T, S, R = unknown>(
source: ResourceSource<S>,
fetcher: ResourceFetcher<S, T, R>,
options?: ResourceOptions<T, S>
): ResourceReturn<T, R>;
type ResourceSource<S> = S | false | null | undefined | (() => S | false | null | undefined);
type ResourceFetcher<S, T, R = unknown> = (source: S, info: ResourceFetcherInfo<T, R>) => T | Promise<T>;
interface ResourceFetcherInfo<T, R = unknown> {
value: T | undefined;
refetching: R | boolean;
}
interface ResourceOptions<T, S = unknown> {
initialValue?: T;
name?: string;
deferStream?: boolean;
ssrLoadFrom?: "initial" | "server";
storage?: (init: T | undefined) => [Accessor<T | undefined>, Setter<T | undefined>];
onHydrated?: (k: S | undefined, info: { value: T | undefined }) => void;
}
type ResourceReturn<T, R = unknown> = [Resource<T>, ResourceActions<T | undefined, R>];
type ResourceActions<T, R = unknown> = {
mutate: Setter<T>;
refetch: (info?: R) => T | Promise<T> | undefined | null;
};Manage async state transitions and provide loading states.
/**
* Starts a transition and returns a promise
* @param fn - Function to run in transition
* @returns Promise that resolves when transition completes
*/
function startTransition(fn: () => unknown): Promise<void>;
/**
* Hook for managing transition state
* @returns Tuple of [isPending accessor, startTransition function]
*/
function useTransition(): [Accessor<boolean>, (fn: () => void) => Promise<void>];
type Transition = [Accessor<boolean>, (fn: () => void) => Promise<void>];Usage Examples:
import { createResource, startTransition, useTransition } from "solid-js";
// Basic resource
const [user] = createResource(fetchUser);
// Resource with source
const [userId, setUserId] = createSignal(1);
const [userData] = createResource(userId, fetchUserById);
// Transitions
function App() {
const [isPending, start] = useTransition();
const handleUpdate = () => {
start(() => {
// This will show pending state
updateSomething();
});
};
return (
<div>
<button onClick={handleUpdate} disabled={isPending()}>
{isPending() ? "Updating..." : "Update"}
</button>
</div>
);
}type Accessor<T> = () => T;
type Setter<T> = {
(value: T): T;
(fn: (prev: T) => T): T;
};
type Signal<T> = [get: Accessor<T>, set: Setter<T>];interface Owner {
owned: Computation<any>[] | null;
cleanups: (() => void)[] | null;
owner: Owner | null;
context: any;
sourceMap?: Set<Computation<any>>;
name?: string;
}
interface Computation<T> {
fn: EffectFunction<any, T>;
state: number;
sources: Computation<any>[] | null;
sourceSlots: number[] | null;
value?: T;
age: number;
updatedAt?: number;
}type Resource<T> = Accessor<T | undefined> & {
loading: boolean;
error: any;
latest: T | undefined;
state: "unresolved" | "pending" | "ready" | "refreshing" | "errored";
};
type ResolvedJSXElement = Exclude<JSX.Element, JSX.ArrayElement>;
type ResolvedChildren = ResolvedJSXElement | ResolvedJSXElement[];Install with Tessl CLI
npx tessl i tessl/npm-solid-js