Skip to content
Layers
Esc
navigateopen⌘Jpreview
On this page

Solid

Solid adapter — LayerClientContext, signal accessors, StackOutlet.

@stainless-code/solid-layers bridges stacks into Solid signals via from. The core is re-exported.

Install

npm install @stainless-code/solid-layers
pnpm add @stainless-code/solid-layers
yarn add @stainless-code/solid-layers
bun add @stainless-code/solid-layers

Peer: solid-js >=1.6.0

Client

Provide a LayerClient through LayerClientContext. Read it with useLayerClient():

import {
  LayerClientContext,
  LayerClient,
  StackOutlet,
  useLayerClient,
} from "@stainless-code/solid-layers";

const client = new LayerClient();

function App() {
  return (
    <LayerClientContext.Provider value={client}>
      <StackOutlet stack="confirm" />
    </LayerClientContext.Provider>
  );
}

createStackHook also returns a bound StackProvider when you want a single-stack factory.

Render a stack

StackOutlet renders registered components with keyed Dynamic updates. For render-prop subscriptions, use StackSubscribe.

Confirm dialog

import {
  layerOptions,
  LayerClientContext,
  LayerClient,
  StackOutlet,
  useLayer,
  type LayerComponentProps,
} from "@stainless-code/solid-layers";

type ConfirmPayload = { title: string };
type ConfirmResponse = boolean;

function ConfirmDialog(props: LayerComponentProps<ConfirmPayload, ConfirmResponse>) {
  return (
    <div role="dialog">
      <h2>{props.payload.title}</h2>
      <button onClick={() => void props.call.end(true)}>Yes</button>
      <button onClick={() => void props.call.end(false)}>No</button>
    </div>
  );
}

const confirm = layerOptions<ConfirmPayload, ConfirmResponse>({
  stack: "confirm",
  key: ["confirm", "remove"],
  component: ConfirmDialog,
});

const client = new LayerClient();

function RemoveButton() {
  const c = useLayer(confirm);
  return (
    <button
      onClick={() => void c.open({ title: "Remove item?" })}
    >
      Remove
    </button>
  );
}

function App() {
  return (
    <LayerClientContext.Provider value={client}>
      <StackOutlet stack="confirm" />
      <RemoveButton />
    </LayerClientContext.Provider>
  );
}
import {
  layerOptions,
  LayerClientContext,
  LayerClient,
  StackOutlet,
  useLayer,
} from "@stainless-code/solid-layers";

function ConfirmDialog(props) {
  return (
    <div role="dialog">
      <h2>{props.payload.title}</h2>
      <button onClick={() => void props.call.end(true)}>Yes</button>
      <button onClick={() => void props.call.end(false)}>No</button>
    </div>
  );
}

const confirm = layerOptions({
  stack: "confirm",
  key: ["confirm", "remove"],
  component: ConfirmDialog,
});

const client = new LayerClient();

function RemoveButton() {
  const c = useLayer(confirm);
  return (
    <button
      onClick={() => void c.open({ title: "Remove item?" })}
    >
      Remove
    </button>
  );
}

function App() {
  return (
    <LayerClientContext.Provider value={client}>
      <StackOutlet stack="confirm" />
      <RemoveButton />
    </LayerClientContext.Provider>
  );
}

Primitives

Options bag plus optional trailing LayerClient. Drive with useLayer(options); observe with useLayerState({ key, … }). Solid-idiomatic aliases: createStack, createQueuedStack, createLayerState, createLayerQueuedState.

Export Role
useStack({ stack?, select?, compare? }, client?) Accessor<T> of the selected stack slice
useQueuedStack({ stack?, select?, compare? }, client?) Queued snapshot accessor
useLayer(options, client?) Drive — wired handle accessors + open() / dismiss() + reactive state / queued / top
useLayerState({ key, stack?, select?, compare? }, client?) ObserveAccessor<LayerState[]> for mounted same-key layers
useLayerQueuedState({ key, stack?, select?, compare? }, client?) Observe — queued same-key layers

Read accessors with () — e.g. useStack({ stack: "confirm" })().

Ergonomic APIs

Export Role
useStackHandles(stack?, rootProps?) { states: Accessor, getCall } for headless rendering
StackSubscribe Render-prop with Accessor<T> child argument
useMutationFlow(call) pending is an Accessor<boolean>; run(fn).orEnd(response)
useLayerGroup(call, options?) Child stack with Outlet component
createStackHook(config?) StackProvider, useAppStack, AppHost, AppLayer

Learn more

Last updated on September 4, 2026

Was this page helpful?