# WebHID API: navigator.hid device access from the web

> Pair a HID device with navigator.hid.requestDevice(), handle connect and disconnect events, and meet the secure-context and activation rules.

**In one line:** WebHID lets a web page request access to a Human Interface Device (HID) —
"a type of device that takes input from or provides output to humans," using the HID
protocol originally built for USB and since implemented over other transports including
Bluetooth — through a permission prompt. MDN marks it **experimental** and **not Baseline**,
"because it does not work in some of the most widely-used browsers."

## Secure context and transient activation

`navigator.hid` is exposed only in secure contexts: both the `Navigator` and
`WorkerNavigator` partial interfaces that add it are annotated `[SecureContext]` in the
spec. Calling `requestDevice()` also requires **transient activation** — the spec rejects
the returned promise with a `SecurityError` `DOMException` if "the relevant global object of
this does not have transient activation," and rejects with `NotSupportedError` if the caller
is not a `window` context.

## Requesting and reusing a device

```js
const devices = await navigator.hid.requestDevice({ filters: [] });
```

`requestDevice()` shows a permission prompt listing candidate devices (an empty `filters`
array matches everything); the user selects a device and clicks Connect. Once a device has
been authorized, `getDevices()` returns it again without prompting:

```js
const devices = await navigator.hid.getDevices();
devices.forEach((device) => {
  console.log(`HID: ${device.productName}`);
});
```

Access to both methods is also gated by a Permissions Policy feature named `"hid"`: the spec
rejects with `SecurityError` if the calling document is not "allowed to use" it.

## Connect and disconnect events

```js
navigator.hid.addEventListener("disconnect", (event) => {
  console.log(`HID disconnected: ${event.device.productName}`);
});
```

The `HID` interface fires matching `connect` and `disconnect` events, each carrying an
`HIDConnectionEvent` with a `device` property, when a previously authorized device is
attached or removed.

## Opening a device and exchanging reports

`HIDDevice.open()` rejects with `InvalidStateError` unless the device's state is `"closed"`;
otherwise it asks the OS to open the device and resolves once open (or rejects with
`NetworkError` on failure). `close()` rejects pending report promises with `AbortError`,
closes the OS handle, and returns the device to the `"closed"` state. `sendReport()`,
`sendFeatureReport()`, and `receiveFeatureReport()` each reject with `InvalidStateError` if
the device is not `"opened"`, and with `TypeError` if the report ID does not match whether
the device's interface uses report IDs.

## Blocked reports

The spec defines a "blocked report" concept: `sendReport()`, `sendFeatureReport()`, and
`receiveFeatureReport()` each check whether the target report is blocked and, if so, reject
with `NotAllowedError`; a blocked input report simply does not fire an `inputreport` event.
The spec separately describes device- and usage-based blocking — for example, blocking by
vendor/product ID or by inspecting the HID usage values assigned to a device's collections
(the spec gives keyboards as an illustrative example of usage-based blocking).

## Availability in workers

MDN notes this feature is available in Web Workers, "except for Shared Web Workers" —
`WorkerNavigator.hid` exposes it in dedicated workers, alongside `Navigator.hid` on the main
thread.

## Feature detection and fallback

```js
async function connectHidDevice() {
  if (!("hid" in navigator)) {
    // WebHID is unsupported here — fall back to a manual pairing UI
    // or another transport instead of calling navigator.hid.
    return null;
  }
  const [device] = await navigator.hid.requestDevice({ filters: [] });
  return device ?? null;
}
```

## Practical checklist

- [ ] Feature-detect `navigator.hid` before calling any WebHID method — it is experimental
      and not Baseline per MDN, so absence is expected in some browsers.
- [ ] Serve the page over HTTPS; `navigator.hid` is exposed only in secure contexts.
- [ ] Call `requestDevice()` only with transient activation (a user gesture), or it rejects
      with `SecurityError`.
- [ ] Call `getDevices()` on later visits to reuse a previously authorized device without a
      new prompt.
- [ ] Check `HIDDevice.opened`/state before calling `sendReport()`,
      `sendFeatureReport()`, or `receiveFeatureReport()` — each rejects with
      `InvalidStateError` on a device that is not open.
- [ ] Do not assume a report will succeed just because the device is open: the spec allows a
      "blocked report" on an open device to be rejected with `NotAllowedError`.
- [ ] Remember one physical device can be represented by more than one `HIDDevice` object.

## Cross-references

- [WebUSB API](/reference/capabilities/web-usb/)
- [Web Bluetooth](/reference/capabilities/web-bluetooth/)