Awaiting results
Await typed responses from a wired handle (or bag-form open), infer types via DataTag, or fire-and-forget with void.
Need a boolean back from a confirm? Wire the declaration, then await confirm.open(...) — Promise<R> with no call-site generic. Awaiting is optional; fire-and-forget is equally first-class.
Typed await
Brand the contract once with layerOptions<P, R>(). The key carries a DataTag, so payload-only open infers R:
import { createLayer } from "@stainless-code/layers";
const confirm = layerOptions<ConfirmPayload, boolean>({
stack: "confirm",
key: ["confirm", "remove"],
component: ConfirmDialog,
});
const c = createLayer(confirm, client);
const ok = await c.open({ title: "Remove?" });
// ^? boolean
Adapters bind the same handle with useLayer / injectLayer / createLayer (see tabs below). You can also brand a key alone with layerKey<R>()(key) when options are inlined at the call site. See Identity and types.
Open from your framework
Adapters ship a wired handle — useLayer(options) (Svelte: createLayer; Angular: injectLayer) — for payload-only open plus reactive state/queued/top:
import { useLayer } from "@stainless-code/react-layers";
function RemoveButton() {
const confirmLayer = useLayer(confirm);
async function handleRemove() {
const ok = await confirmLayer.open({ title: "Remove?" });
// ^? boolean
if (ok) {
/* … */
}
}
return (
<button type="button" onClick={() => void handleRemove()}>
Remove
</button>
);
}import { useLayer } from "@stainless-code/preact-layers";
function RemoveButton() {
const confirmLayer = useLayer(confirm);
async function handleRemove() {
const ok = await confirmLayer.open({ title: "Remove?" });
// ^? boolean
if (ok) {
/* … */
}
}
return (
<button type="button" onClick={() => void handleRemove()}>
Remove
</button>
);
}import { useLayer } from "@stainless-code/solid-layers";
function RemoveButton() {
const confirmLayer = useLayer(confirm);
async function handleRemove() {
const ok = await confirmLayer.open({ title: "Remove?" });
// ^? boolean
if (ok) {
/* … */
}
}
return (
<button type="button" onClick={() => void handleRemove()}>
Remove
</button>
);
}import { Component } from "@angular/core";
import { injectLayer } from "@stainless-code/angular-layers";
@Component({ /* … */ })
class RemoveButton {
private confirmLayer = injectLayer(confirm);
async remove() {
const ok = await this.confirmLayer.open({ title: "Remove?" });
// ^? boolean
if (ok) {
/* … */
}
}
}<script setup lang="ts">
import { useLayer } from "@stainless-code/vue-layers";
const confirmLayer = useLayer(confirm);
async function remove() {
const ok = await confirmLayer.open({ title: "Remove?" });
// ^? boolean
if (ok) {
/* … */
}
}
</script><script lang="ts">
import { createLayer } from "@stainless-code/svelte-layers";
const confirmLayer = createLayer(confirm);
async function remove() {
const ok = await confirmLayer.open({ title: "Remove?" });
// ^? boolean
if (ok) {
/* … */
}
}
</script><script lang="ts">
import { createLayer } from "@stainless-code/svelte-layers/store";
const confirmLayer = createLayer(confirm);
async function remove() {
const ok = await confirmLayer.open({ title: "Remove?" });
// ^? boolean
if (ok) {
/* … */
}
}
</script>Bag-form (escape hatch)
client.open({ …layerOptions, payload }) stays valid — headless call sites, dynamic keys, or when you already hold a LayerClient:
const ok = await client.open({ ...confirm, payload: { title: "Remove?" } });
// ^? boolean
See Migration — bag-form remains first-class alongside Drive handles.
Fire-and-forget
When a layer needs no return value, omit the response generic (defaults to void) and skip await:
import { createLayer } from "@stainless-code/layers";
const about = layerOptions({
stack: "modal",
key: ["about"],
component: About,
});
const c = createLayer(about, client);
void c.open();
The layer dismisses itself — typically via call.dismiss() inside the component. Use void to signal intentional fire-and-forget when your linter flags floating promises.
Edge cases
loadFnerrors reject the promise — see Error handling.- Validation failures reject with
PayloadValidationErrorbefore mount — see Payload validation. - System teardown (
cancelAll, parent-dismiss child drain, group dispose, host disconnect) rejects withLayerCancelledError— narrow withisLayerCancelledError; see Error handling. - Serial stacks queue later opens; the promise resolves only when the layer activates and ends — see Serial queues.