Skip to content
Layers
Esc
navigateopen⌘Jpreview
On this page

Vue

Vue adapter — provideLayerClient, composition API hooks, StackOutlet.

@stainless-code/vue-layers bridges stacks into Vue 3 composition API refs. The core is re-exported.

Install

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

Peer: vue >=3.3.0

Client

Call provideLayerClient() in a parent setup() (creates a LayerClient when omitted). Descendants read it with useLayerClient():

<script setup lang="ts">
import { provideLayerClient, StackOutlet } from "@stainless-code/vue-layers";

provideLayerClient();
</script>

<template>
  <StackOutlet stack="confirm" />
</template>

Render a stack

StackOutlet renders registered component entries. For scoped-slot-style subscriptions, use StackSubscribe or useStack({ stack, select }) directly in setup().

Confirm dialog

<script setup lang="ts">
import {
  layerOptions,
  provideLayerClient,
  StackOutlet,
  useLayer,
  type LayerComponentProps,
} from "@stainless-code/vue-layers";

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

const ConfirmDialog = defineComponent({
  props: {
    call: { type: Object, required: true },
    payload: { type: Object, required: true },
  },
  setup(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,
});

provideLayerClient();
const c = useLayer(confirm);

async function remove() {
  await c.open({ title: "Remove item?" });
}
</script>

<template>
  <StackOutlet stack="confirm" />
  <button @click="remove">Remove</button>
</template>

Primitives

Options bag plus optional trailing LayerClient. Drive with useLayer(options); observe with useLayerState({ key, … }).

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

Ergonomic APIs

Export Role
useStackHandles(stack?, rootProps?) { states: Ref, getCall } for headless rendering
StackSubscribe Scoped-slot subscription (#default="{ value }")
useMutationFlow(call) pending is a Ref<boolean>; run(fn).orEnd(response)
useLayerGroup(call, options?) Child stack with Outlet component
createStackHook(config?) StackProvider, useAppStack, AppHost, AppLayer components

Learn more

Last updated on July 18, 2026

Was this page helpful?