use-web-locks
Coordinate work across tabs and workers with the Web Locks API.
| Package | @vizejs/composable/use-web-locks |
| Own the source | vize lib pull composable:use-web-locks |
| Runtime exports | useWebLocks |
| Gzip budget | 2560 B |
Minimal setup
Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).
vp install @vizejs/composable
Import the entry directly. Call lifecycle-bound utilities inside <script setup> so cleanup follows the component scope; consult the runtime contract for this entry's SSR and hydration behavior.
import { useWebLocks } from "@vizejs/composable/use-web-locks";
Try it
Run one export at a time
Coordinate exclusive work across tabs with the Web Locks API.
What to observe: Start export holds the export lock. Try another export reports that one is already running; after Finish export it starts.
The lock is held until the callback's promise settles. ifAvailable: true returns immediately with acquired: false instead of waiting.
Compare the initial and interacted states


Copy the example
Save this complete SFC in your Vue project. Its public imports and source are the same ones executed in the preview.
<script setup lang="ts">
import { ref } from "vue";
import { useWebLocks } from "@vizejs/composable/use-web-locks";
const { request, held } = useWebLocks();
const message = ref("Idle.");
let finish: (() => void) | undefined;
function startExport() {
void request("export", () => new Promise<void>((resolve) => (finish = resolve)));
message.value = "Export running in this tab.";
}
async function tryExport() {
const attempt = await request("export", () => "second export", { ifAvailable: true });
message.value = attempt.acquired
? "Started another export."
: "Another export is already running.";
}
function stopExport() {
finish?.();
message.value = "Export finished.";
}
</script>
<template>
<div class="composable-example">
<p>Make sure only one tab runs an export at a time.</p>
<div class="example-actions">
<button type="button" @click="startExport">Start export</button>
<button type="button" @click="tryExport">Try another export</button>
<button type="button" @click="stopExport">Finish export</button>
</div>
<output aria-live="polite">{{ message }} Locks held: {{ held.join(", ") || "none" }}</output>
</div>
</template>
Runtime contract
| Utility | Category | Stability | SSR | Hydration | Cleanup | Targets | Host globals | Uses |
|---|---|---|---|---|---|---|---|---|
useWebLocks |
async | experimental | deterministic-fallback | caller-managed | reactive-scope, caller | web, desktop | AbortController, DOMException, window |
tryOnScopeDispose |
API
useWebLocks
Coordinate work across tabs and workers with the Web Locks API. request runs the callback while the named lock is held and resolves with its result; with ifAvailable it resolves with a discriminated { acquired } outcome instead of waiting. held and pending track the lock names requested through this composable. Requests still waiting when the owning reactive scope stops are aborted; locks already held are released when their callbacks settle. Outside a scope, pass a signal to own cancellation. Server rendering: nothing is requested, supported is false and the name lists are empty.
function useWebLocks(options: UseWebLocksOptions = {}): WebLocksControls
const locks = useWebLocks();
await locks.request("sync", async () => syncOutbox());
const attempt = await locks.request("leader", runLeader, { ifAvailable: true });
Types
WebLockLike
Granted lock handed to a request callback.
| Member | Type | Description |
|---|---|---|
name |
string |
Lock name. |
mode |
WebLockMode |
Granted mode. |
WebLockInfo
One entry of a lock manager snapshot.
| Member | Type | Description |
|---|---|---|
name? |
string | undefined |
Lock name. |
mode? |
WebLockMode | undefined |
Requested or granted mode. |
clientId? |
string | undefined |
Identifier of the client holding or requesting the lock. |
WebLocksSnapshot
Snapshot returned by WebLocksControls.query.
| Member | Type | Description |
|---|---|---|
held |
readonly WebLockInfo[] |
Locks currently held by any client of the origin. |
pending |
readonly WebLockInfo[] |
Requests currently waiting for a lock. |
WebLockManagerRequestOptions
Options forwarded to LockManager.request.
| Member | Type | Description |
|---|---|---|
mode |
WebLockMode |
Requested mode. |
ifAvailable? |
boolean |
Only grant the lock when it is immediately available. |
steal? |
boolean |
Release any held lock of the same name and grant this request. |
signal? |
AbortSignal |
Abort the request while it is pending. |
LockManagerLike
Minimal LockManager (navigator.locks) consumed by useWebLocks.
| Member | Type | Description |
|---|---|---|
request |
(name: string, options: WebLockManagerRequestOptions, callback: (lock: WebLockLike | null) => unknown) => Promise<unknown> |
Request a lock and run callback while it is held. |
query |
() => Promise<{ /** Held locks. */ readonly held?: readonly WebLockInfo[] | undefined; /** Pending requests. */ readonly pending?: readonly WebLockInfo[] | undefined; }> |
Snapshot the origin's held and pending locks. |
UseWebLocksOptions
Options for useWebLocks.
| Member | Type | Description |
|---|---|---|
locks? |
MaybeRefOrGetter<LockManagerLike | null | undefined> |
Lock manager for alternate runtimes and tests. |
WebLockRequestOptions
Per-request options for WebLocksControls.request.
| Member | Type | Description |
|---|---|---|
mode? |
WebLockMode |
Requested mode. |
ifAvailable? |
boolean |
Resolve with { acquired: false } instead of waiting when the lock is busy. |
steal? |
boolean |
Preempt any holder of the lock (exclusive mode only). |
signal? |
AbortSignal |
Abort the request while it is still pending. |
WebLocksControls
Reactive state and actions returned by useWebLocks.
| Member | Type | Description |
|---|---|---|
supported |
ComputedRef<boolean> |
Whether the Web Locks API is available. |
held |
Readonly<Ref<readonly string[]>> |
Names of locks requested through this composable that are currently held. |
pending |
Readonly<Ref<readonly string[]>> |
Names of locks requested through this composable that are still waiting. |
error |
Readonly<ShallowRef<unknown>> |
Most recent request failure (including aborts), cleared by the next grant. |
request |
WebLockRequest |
Request a lock. Rejects with a tagged TypeError for invalid option combinations, a tagged Error when unsupported, the host's AbortError when aborted, or the callback's rejection. |
query |
() => Promise<WebLocksSnapshot> |
Snapshot the origin's locks. |