loading
Note:
Try it with two tabs Locks are shared across every tab and worker of the origin. Open this page in a second tab, acquire the lock in tab A, then press Acquire in tab B - B's request waits (see it under Pending in the Query section) until A releases. Web Locks work in all modern browsers and require a secure context.

Check support

IsSupported

Returns true when the runtime exposes navigator.locks.

C#
var supported = await webLocks.IsSupported();
Live sample
support output
Results will appear here when you interact with the samples.

Acquire and release

Acquire

Acquire hands you an IAsyncDisposable handle; dispose it to release the lock - the natural .NET counterpart to the callback-scoped JS API. By default the call waits until the lock is granted. With ifAvailable set to true it returns null immediately when the lock is taken, and steal transfers ownership from the current holder (use with care). Shared mode allows multiple concurrent holders, exclusive (the default) allows one.

C#
await using var handle = await webLocks.Acquire("my-resource");

// ... the lock is held here ...

// released when the handle is disposed

// non-blocking attempt:
var maybe = await webLocks.Acquire("my-resource", ifAvailable: true);
if (maybe is null)
{
    // somebody else holds it
}
Live sample
acquire output
Results will appear here when you interact with the samples.

Run a guarded callback

Run

Run acquires the lock, executes your callback and releases automatically - even when the callback throws. This demo holds the lock for three seconds; race it from a second tab to watch the other request queue up.

C#
await webLocks.Run("my-resource", async () =>
{
    // the lock is held for the duration of this callback
    await Task.Delay(3000);
});
// released automatically
Live sample
run output
Results will appear here when you interact with the samples.

Query the lock manager

Query

Returns a snapshot of the origin's lock manager: every currently held lock and every pending request, each with its name, mode and an opaque client id identifying the tab or worker. Useful for diagnostics - acquire a lock in another tab first, then query here.

C#
var snapshot = await webLocks.Query();

foreach (var held in snapshot.Held)
{
    // held.Name, held.Mode ("exclusive" / "shared"), held.ClientId
}

foreach (var pending in snapshot.Pending)
{
    // requests still waiting for the lock
}
Live sample
query output
Results will appear here when you interact with the samples.
Warning:
Cooperative, not mandatory Web Locks only coordinate code that opts into them - they do not protect storage or any other resource from code that simply ignores the lock. A lock held by a tab is released automatically when that tab closes or navigates away, so stale locks cannot outlive their holder.

API reference

Member
Signature
Description
IsSupported
ValueTask<bool> IsSupported()
True when the runtime exposes navigator.locks.
Acquire
ValueTask<IAsyncDisposable?> Acquire(string name, WebLockMode mode = WebLockMode.Exclusive, bool ifAvailable = false, bool steal = false, CancellationToken cancellationToken = default)
Acquires the named lock; dispose the returned handle to release. Returns null when ifAvailable is true and the lock is not free.
Run
ValueTask Run(string name, Func<ValueTask> action, WebLockMode mode = WebLockMode.Exclusive, bool ifAvailable = false, bool steal = false, CancellationToken cancellationToken = default)
Runs the action while holding the named lock and releases automatically.
Query
ValueTask<WebLockSnapshot> Query()
Returns the current state of the lock manager.
WebLockMode
enum WebLockMode { Exclusive, Shared }
Exclusive (default) allows a single holder; Shared allows multiple concurrent holders.
WebLockSnapshot.Held
WebLockInfo[] Held { get; set; }
Locks currently held across the origin.
WebLockSnapshot.Pending
WebLockInfo[] Pending { get; set; }
Requests still waiting for their lock.
WebLockInfo.Name
string Name { get; set; }
The lock's name.
WebLockInfo.Mode
string Mode { get; set; }
The lock's mode: exclusive or shared.
WebLockInfo.ClientId
string ClientId { get; set; }
Opaque id of the tab or worker holding / requesting the lock.
An unhandled error has occurred. Reload 🗙