loading
Warning:
Chromium only The Device Posture API ships in Chromium-based browsers. Everything that is not a foldable reports Continuous, so a layout can branch on the posture without special-casing ordinary hardware - which is also why this demo will report Continuous on a normal machine rather than failing.
Note:
Posture, not geometry The posture says that the device is folded, not where the fold is. The fold's position comes from CSS - env(viewport-segment-width 0 0) and friends - so a two-pane layout reads both: this API to decide whether to split, CSS to decide where.

Read the posture

IsSupported / GetPosture

GetPosture returns Continuous or Folded. On an unsupported browser it returns Continuous rather than throwing, which is the honest answer for hardware that cannot fold.

C#
@inject Bit.Butil.DevicePosture devicePosture

var supported = await devicePosture.IsSupported();
var posture = await devicePosture.GetPosture();   // Continuous | Folded
Live sample
posture output
Results will appear here when you interact with the samples.

Watch it change

SubscribeChange / RemoveChange / RemoveAllChanges

Fires when the device is folded or unfolded. Dispose the subscription - or call RemoveChange with its id - to detach; RemoveAllChanges detaches every listener this service registered.

C#
await using var subscription = await devicePosture.SubscribeChange(posture =>
{
    // posture is DevicePostureType.Continuous or .Folded
});

// or, by id:
await devicePosture.RemoveChange(subscription.Id);
await devicePosture.RemoveAllChanges();
Live sample
change output
Results will appear here when you interact with the samples.

API reference

Member
Signature
Description
IsSupported
ValueTask<bool> IsSupported()
True when the runtime exposes navigator.devicePosture. Returns default (false) during prerender/SSR instead of throwing.
GetPosture
ValueTask<DevicePostureType> GetPosture()
The current posture; Continuous on an unsupported browser.
SubscribeChange
ValueTask<ButilSubscription> SubscribeChange(Action<DevicePostureType> handler)
Runs the handler whenever the device is folded or unfolded.
RemoveChange
ValueTask RemoveChange(Guid id)
Detaches one listener by the id its subscription carries.
RemoveAllChanges
ValueTask RemoveAllChanges()
Detaches every posture listener registered through this instance.
DisposeAsync
ValueTask DisposeAsync()
Detaches every listener and releases the JS callback reference.
InvokeDevicePostureChange
void InvokeDevicePostureChange(Guid id, string type)
JSInvokable interop plumbing for the change event - not intended for app code.
DevicePostureType
enum DevicePostureType { Continuous, Folded }
A flat screen, or one folded across a hinge.
An unhandled error has occurred. Reload 🗙