Skip to content

useBattery

React hook to track the battery status of a user's device.

Add the hook via the CLI:

sh
npx @novajslabs/cli add useBattery
sh
npx @novajslabs/cli add useBattery
sh
pnpm dlx @novajslabs/cli add useBattery

Or copy and paste the code into your project:

ts
import { useState, useEffect } from "react";

interface BatteryManager {
  level: number;
  charging: boolean;
  chargingTime: number;
  dischargingTime: number;
  addEventListener(
    type: string,
    listener: EventListener | EventListenerObject | null,
    options?: boolean | AddEventListenerOptions
  ): void;
  removeEventListener(
    type: string,
    listener: EventListener | EventListenerObject | null,
    options?: boolean | EventListenerOptions
  ): void;
}

interface BatteryState {
  supported: boolean;
  loading: boolean;
  level: number | null;
  charging: boolean | null;
  chargingTime: number | null;
  dischargingTime: number | null;
}

interface NavigatorWithBattery extends Navigator {
  getBattery: () => Promise<BatteryManager>;
}

export const useBattery = () => {
  const [batteryState, setBatteryState] = useState<BatteryState>({
    supported: true,
    loading: true,
    level: null,
    charging: null,
    chargingTime: null,
    dischargingTime: null,
  });

  useEffect(() => {
    const _navigator = navigator as NavigatorWithBattery;
    let battery: BatteryManager;

    const handleBatteryChange = () => {
      setBatteryState({
        supported: true,
        loading: false,
        level: battery.level,
        charging: battery.charging,
        chargingTime: battery.chargingTime,
        dischargingTime: battery.dischargingTime,
      });
    };

    if (!_navigator.getBattery) {
      setBatteryState((batteryState) => ({
        ...batteryState,
        supported: false,
        loading: false,
      }));
      return;
    }

    _navigator.getBattery().then((_battery) => {
      battery = _battery;
      handleBatteryChange();

      _battery.addEventListener("levelchange", handleBatteryChange);
      _battery.addEventListener("chargingchange", handleBatteryChange);
      _battery.addEventListener("chargingtimechange", handleBatteryChange);
      _battery.addEventListener("dischargingtimechange", handleBatteryChange);
    });

    return () => {
      if (battery) {
        battery.removeEventListener("levelchange", handleBatteryChange);
        battery.removeEventListener("chargingchange", handleBatteryChange);
        battery.removeEventListener("chargingtimechange", handleBatteryChange);
        battery.removeEventListener(
          "dischargingtimechange",
          handleBatteryChange
        );
      }
    };
  }, []);

  return batteryState;
};
js
import { useState, useEffect } from "react";

export const useBattery = () => {
  const [batteryState, setBatteryState] = useState({
    supported: true,
    loading: true,
    level: null,
    charging: null,
    chargingTime: null,
    dischargingTime: null,
  });

  useEffect(() => {
    let battery;

    const handleBatteryChange = () => {
      setBatteryState({
        supported: true,
        loading: false,
        level: battery.level,
        charging: battery.charging,
        chargingTime: battery.chargingTime,
        dischargingTime: battery.dischargingTime,
      });
    };

    if (!navigator.getBattery) {
      setBatteryState((batteryState) => ({
        ...batteryState,
        supported: false,
        loading: false,
      }));
      return;
    }

    navigator.getBattery().then((_battery) => {
      battery = _battery;
      handleBatteryChange();

      _battery.addEventListener("levelchange", handleBatteryChange);
      _battery.addEventListener("chargingchange", handleBatteryChange);
      _battery.addEventListener("chargingtimechange", handleBatteryChange);
      _battery.addEventListener("dischargingtimechange", handleBatteryChange);
    });

    return () => {
      if (battery) {
        battery.removeEventListener("levelchange", handleBatteryChange);
        battery.removeEventListener("chargingchange", handleBatteryChange);
        battery.removeEventListener("chargingtimechange", handleBatteryChange);
        battery.removeEventListener(
          "dischargingtimechange",
          handleBatteryChange
        );
      }
    };
  }, []);

  return batteryState;
};

Requirements

React 16.8 or higher

Return values

supported

Type: boolean

Represents whether the Battery Status API is supported in the browser (true) or not (false).

loading

Type: boolean

Represents if the battery information is loading (true) or not (false).

level

Type: number | null

Represents the level of the battery. 0.0 means that the battery is discharged, and 1.0 means the battery is fully charged.

charging

Type: boolean | null

Represents whether the battery is charging (true) or not (false).

chargingTime

Type: number | null

Represents the time remaining in seconds until the battery is completely charged.

dischargingTime

Type: number | null

Represents the time remaining in seconds until the battery is completely discharged.

Example

tsx
import { useBattery } from "./hooks/useBattery";

const App = () => {
  const { level, charging } = useBattery();

  return (
    <div>
      <p>Battery level:{level && level * 100}</p>
      <p>{charging ? "Battery charging" : "Battery not charging"}</p>
    </div>
  );
};

export default App;

Use cases

Here are some use cases where this React hook is useful:

  • Displaying the battery level in a user interface
  • Low battery level notifications