@excom/provider-orientation
v0.1.4
Published
<provider-orientation> custom element
Maintainers
Readme
provider-orientation
Declarative device orientation / compass — request a heading, read the normalized bearing from attributes/state.
Features
- Attribute-driven Request + read a compass heading through attributes
- Normalized bearing
0–360°from magnetic north on both iOS and Android, one shape either way - Throttled updates
compass-throttle-mscaps update frequency (Android can fire 60-200 Hz) - iOS-aware Works with the required user-gesture permission flow
Installation
@excom/provider-orientation v0.1.4
pnpm add @excom/provider-orientationnpm install @excom/provider-orientationyarn add @excom/provider-orientationImport
import "@excom/provider-orientation";Usage
Requires a user gesture on iOS. DeviceOrientationEvent
.requestPermission() must run synchronously inside a click handler or
Safari denies it — so set is-paused and invoke the --request command
from a button rather than relying on the connect-time auto-request (the
handler runs in a microtask of the click, inside its user activation):
<button type="button" command="--request" commandfor="compass">
Enable compass
</button>
<provider-orientation id="compass" is-paused></provider-orientation>compass-needle {
transform: rotate(calc(var(--bearing, 0) * 1deg));
}Android and desktop browsers with a sensor don't require permission and will start listening as soon as the request fires; browsers with no sensor at all simply never report a reading.
API Reference
Attributes
| Name | Surface | Type | Default | Values | Description |
| --- | --- | --- | --- | --- | --- |
| is-paused | option | boolean | | | Skip requesting on connect. On iOS this is effectively required (a connect-time request happens outside a user gesture and will be denied) — pair with provider-orientation-request from a click handler instead (see class docs). |
| compass-throttle-ms | option | number | 100 | | Minimum ms between provider-orientation-success updates. Android can fire deviceorientationabsolute at 60-200 Hz; without throttling that floods listeners and CSS/Quark bindings. |
| is-requesting | state | boolean | | | iOS only: the permission request is pending (between provider-orientation-request and the user's response). |
| is-success | state | boolean | | | Listening for orientation updates (permission granted where required). Stays set across updates. |
| is-error | state | boolean | | | The permission request was denied, or listening failed to start. |
Provision
| Name | Type | Description |
| --- | --- | --- |
| provision | ProviderOrientationSuccess ({ bearing: number; alpha: number \| null; }) | Latest reading: { bearing, alpha } on success, or the error on failure. Not reflected as an attribute. |
Fires
| Name | Type | Description |
| --- | --- | --- |
| provider-orientation-success | ProviderOrientationSuccessEvent (CustomEvent & { type: "provider-orientation-success"; detail: { bearing: number; alpha: number \| null; }; bubbles: true; cancelable: true; composed: true }) | Dispatched on every compass update (throttled by compass-throttle-ms). bearing is normalized 0-360°; alpha is the raw DeviceOrientationEvent.alpha where available. |
| provider-orientation-error | ProviderOrientationErrorEvent (CustomEvent & { type: "provider-orientation-error"; detail: string \| Error; bubbles: true; cancelable: true; composed: true }) | Dispatched when the permission request is denied, or fails for any other reason. |
Commands
| Command | Action |
| --- | --- |
| --request | Requests permission (iOS) and starts listening for orientation updates. Invoke it from a button (<button command="--request" commandfor="…">) so the user activation is there. |
Default actions
| Event | Default behavior (unless preventDefault() is called) |
| --- | --- |
| provider-orientation-success | Stores { bearing, alpha } in provision and sets is-success (clearing is-requesting / is-error). |
| provider-orientation-error | Stores the error in provision and sets is-error (clearing is-requesting / is-success). |
Examples
Request on click
<div>
<button type="button" command="--request" commandfor="orient">
Enable compass
</button>
<provider-orientation id="orient" is-paused>
<output></output>
</provider-orientation>
<p class="status">No reading yet — click above. Requires a device
sensor (desktop browsers usually have none).</p>
<quark-sheet>
provider-orientation {
$reading: prop("provision");
&[is-success] output {
content: if($reading.bearing != null: "Heading #{$reading.bearing.toFixed(0)}°"; else: "Listening — no reading yet.");
}
&[is-error] output { content: $reading.message or $reading; }
}
</quark-sheet>
</div>Release notes
0.1.1 (2026-09-23)
- Ship only dist (and declared extras) in the npm tarball; drop build logs, tests and sources
Full documentation: https://nucleus.excom.dev/packages/provider-orientation
