npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@beacio/react

v1.0.0

Published

React hooks for Bluetooth Low Energy — useDevice, useScan, useProfile. Real-time BLE data in React

Readme

@beacio/react

npm version TypeScript

React hooks and components for Web Bluetooth. Works with the WebBLE Safari Extension for iOS support.

Installation

npm install @beacio/react @beacio/core

Add the polyfill import to your app entry file:

import '@beacio/core/auto';

Quick Start

import { WebBLEProvider, useBluetooth, useDevice } from '@beacio/react';
import type { WebBLEDevice } from '@beacio/core';

function App() {
  return (
    <WebBLEProvider>
      <HeartRateMonitor />
    </WebBLEProvider>
  );
}

function HeartRateMonitor() {
  const { requestDevice } = useBluetooth();
  const [device, setDevice] = useState<WebBLEDevice | null>(null);
  const { isConnected, connect, disconnect } = useDevice(device, { autoReconnect: true });

  const handlePair = async () => {
    // Must be called from a user gesture (button click)
    const d = await requestDevice({ filters: [{ services: ['heart_rate'] }] });
    if (d) setDevice(d);
  };

  return (
    <div>
      {!device && <button onClick={handlePair}>Pair</button>}
      {device && !isConnected && <button onClick={connect}>Connect</button>}
      {isConnected && <button onClick={disconnect}>Disconnect</button>}
    </div>
  );
}

Hooks

useBluetooth()

Main hook for Bluetooth availability and device requests.

import { useBluetooth } from '@beacio/react';

const {
  isAvailable,          // Web Bluetooth available?
  isExtensionInstalled, // WebBLE extension installed?
  requestDevice,        // Request device (must be called from user gesture)
  getDevices,           // Get previously paired devices
  ble,                  // Core WebBLE instance
  backgroundSync,       // Background sync API
  peripheral,           // Peripheral mode API
  error,
} = useBluetooth();

useDevice(device, options?)

Manage a device's connection lifecycle with optional auto-reconnect.

import { useDevice } from '@beacio/react';

const {
  connectionState,   // 'disconnected' | 'connecting' | 'connected' | 'disconnecting'
  isConnected,
  isConnecting,
  connect,
  disconnect,
  services,          // Discovered GATT services
  error,
  autoReconnect,     // Current auto-reconnect state
  setAutoReconnect,  // Toggle auto-reconnect
  reconnectAttempt,  // Current reconnect attempt number (0 = not reconnecting)
} = useDevice(device, {
  autoReconnect: true,
  reconnectAttempts: 3,
  reconnectDelay: 1000,
  reconnectBackoffMultiplier: 2,
  onReconnectAttempt: (attempt, delayMs) => {},
  onReconnectSuccess: (attempt) => {},
  onReconnectFailure: (error, attempt, willRetry) => {},
});

useCharacteristic(device, serviceUUID, characteristicUUID)

Read, write, and subscribe to a BLE characteristic. All operations delegate to the core SDK.

import { useCharacteristic } from '@beacio/react';

const {
  value,              // Latest DataView value
  isNotifying,        // Currently subscribed?
  read,               // () => Promise<DataView | null>
  write,              // (value: BufferSource) => Promise<void>
  writeWithoutResponse,
  subscribe,          // (handler: (value: DataView) => void) => Promise<void>
  unsubscribe,
  error,
} = useCharacteristic(device, 'heart_rate', 'heart_rate_measurement');

// Read a value
const data = await read();

// Write a value
await write(new Uint8Array([0x01, 0x02]));

// Subscribe to notifications
await subscribe((value) => {
  console.log('Heart rate:', value.getUint8(1));
});

useNotifications(device, service, characteristic, options?)

Subscribe to characteristic notifications with a rolling history.

import { useNotifications } from '@beacio/react';

const {
  value,          // Latest DataView
  history,        // Array<{ timestamp: Date, value: DataView }>
  isSubscribed,
  subscribe,      // () => Promise<void>
  unsubscribe,
  clear,          // Clear history
  error,
} = useNotifications(device, 'heart_rate', 'heart_rate_measurement', {
  autoSubscribe: true,
  maxHistory: 100,
});

useScan()

Scan for nearby BLE devices.

import { useScan } from '@beacio/react';

const {
  scanState,  // 'idle' | 'scanning' | 'stopped'
  devices,    // WebBLEDevice[]
  start,      // (options?: ScanOptions) => Promise<void>
  stop,
  clear,
  error,
} = useScan();

await start({
  filters: [{ namePrefix: 'Device' }],
  keepRepeatedDevices: true,
});

Components

<WebBLEProvider>

Required context provider. Optionally accepts a pre-configured WebBLE instance.

import { WebBLEProvider } from '@beacio/react';

// Auto-creates WebBLE instance
<WebBLEProvider config={{ apiKey: 'wbl_xxxxx', operatorName: 'MyApp' }}>
  <App />
</WebBLEProvider>

// Or pass an existing instance (useful for testing)
<WebBLEProvider ble={existingBleInstance}>
  <App />
</WebBLEProvider>

<DeviceScanner>

Device selection UI with scan controls.

import { DeviceScanner } from '@beacio/react';

<DeviceScanner
  filters={[{ services: ['heart_rate'] }]}
  onDeviceSelected={(device) => setDevice(device)}
  autoConnect
  maxDevices={10}
  scanDuration={30000}
/>

<ConnectionStatus>

Connection state indicator dot.

import { ConnectionStatus } from '@beacio/react';

<ConnectionStatus device={device} className="status-dot" />

<InstallationWizard>

Guides users through WebBLE extension installation on Safari iOS.

import { InstallationWizard } from '@beacio/react';

<InstallationWizard
  onComplete={() => console.log('Extension installed!')}
/>

Error Handling

All hooks return a WebBLEError with .code and .suggestion fields:

const { error } = useDevice(device);

if (error) {
  console.log(error.code);       // e.g. 'GATT_OPERATION_FAILED'
  console.log(error.suggestion);  // e.g. 'Check that the device is in range'
}

TypeScript

Types are re-exported from @beacio/core for convenience:

import type { WebBLEDevice, WebBLEError, RequestDeviceOptions } from '@beacio/react';
import type { ConnectionState, UseDeviceReturn } from '@beacio/react';

Browser Support

| Browser | Support | Notes | |---------|---------|-------| | Safari iOS | Full | Requires WebBLE Extension | | Chrome 56+ | Full | Native Web Bluetooth | | Edge 79+ | Full | Native Web Bluetooth |

License

MIT