DEV Community

Cover image for Just for Fun: Create a Battery Indicator with React (Works Only in Chrome)
Alex
Alex

Posted on • Originally published at Medium

Just for Fun: Create a Battery Indicator with React (Works Only in Chrome)

In this article, we’re going to build a fun project — a battery indicator component using React. This component will show you the current battery level and whether your device is charging.

Green battery

However, our battery indicator will rely on the Navigator.getBattery() method to retrieve battery information which is not supported by Mozilla and Safari browsers. And also it’s available only in secure contexts (HTTPS).

This means that our component will only work on Chrome and other Chromium-based browsers like Edge.

getBattery function browser compatibility

So, that’s why it’s more of a fun project than a practical one.

Let’s get started!

1. Create a new React project using Vite and the React template.

Vite logo

Run the following commands to create a new React project using Vite and the React template.

npm create vite@latest battery-indicator - - template react
cd battery-indicator
npm install
Enter fullscreen mode Exit fullscreen mode

2. Install Tailwind CSS.

Tailwind CSS Logo

We’ll use Tailwind CSS to style our battery indicator component. Run the following commands to install Tailwind CSS and its dependencies.

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
Enter fullscreen mode Exit fullscreen mode

Update the tailwind.config.js file to include the following:

/** @type {import('tailwindcss').Config} */
export default {
  content: ['./index.html', './src/**/*.{js,ts,jsx}'],
  theme: {
    extend: {},
  },
  plugins: [],
}
Enter fullscreen mode Exit fullscreen mode

Then add @tailwind directives on top of the src/index.css file.

@tailwind base;
@tailwind components;
@tailwind utilities;
Enter fullscreen mode Exit fullscreen mode

3. Create the battery indicator component.

Create a new file called BatteryIndicator.jsx in the src/components folder. This file will contain the battery indicator component.

Let’s start with the battery info state and a function to update the battery info.

// Initial battery info: battery level: 0-100, charging status: true/false, supported by the browser: true/false 
const initialBatteryInfo = { level: 0, charging: false, supported: true };

// Battery info state
const [batteryInfo, setBatteryInfo] = useState(initialBatteryInfo);

// Update the battery info
const updateBatteryInfo = (battery) => {
  setBatteryInfo({ level: battery.level * 100, charging: battery.charging, supported: true });
};
Enter fullscreen mode Exit fullscreen mode

We have to be sure that the browser supports the Battery Status API before we can use it. To do this, we can check if the getBattery method is available in the navigator object by navigator.getBattery. If it’s available, we can use it to get the battery status. If it’s not, we set the supported property of the battery info state to false.

Then, we use the useEffect hook to check if the browser supports the Battery Status API and setup the event listeners for the battery status changes.

The function that provides the battery status is navigator.getBattery(). It’s an async function so we need to use await to resolve it.

useEffect(() => {
  // Check if the browser supports the Battery Status API and setup the event listeners
  const checkBatteryAPIAndSetup = async () => {
    if (navigator.getBattery) {
      try {
        // Get the battery status
        const battery = await navigator.getBattery();
        updateBatteryInfo(battery);

        // Setup the event listeners for the battery status changes
        battery.addEventListener('chargingchange', () => updateBatteryInfo(battery));
        battery.addEventListener('levelchange', () => updateBatteryInfo(battery));
      } catch (error) {
        console.error('Battery status is not supported.');
        setBatteryInfo((prev) => ({ ...prev, supported: false }));
      }
    } else {
      console.error('Battery status is not supported.');
      setBatteryInfo((prev) => ({ ...prev, supported: false }));
    }
  };

  checkBatteryAPIAndSetup();
}, []);
Enter fullscreen mode Exit fullscreen mode

Now, let’s create the UI for the battery indicator component. It will consist of the battery level bar, the battery level text, and the charging icon.

// Component to display the battery info
const BatteryInfo = ({ batteryInfo }) => (
    <div className={`w-32 h-14 border-2 ${batteryInfo.charging ? 'border-green-500' : 'border-gray-500'} rounded-lg flex items-center justify-start overflow-hidden relative`}>
      {/* Battery level bar */}
      <div
        className={`${batteryInfo.level > 20 ? 'bg-green-300' : 'bg-red-500'} h-full`}
        style={{ width: `${batteryInfo.level}%` }}
      ></div>
      {/* Battery level text */}
      <div className="absolute w-full h-full flex items-center justify-center text-lg font-semibold">
        {batteryInfo.level.toFixed(0)}%
      </div>
      {batteryInfo.charging && <ChargingIcon />}
    </div>
);
Enter fullscreen mode Exit fullscreen mode

The battery level bar has width that corresponds to the battery level. We use the style attribute to set the width of the bar based on the battery level. We use the toFixed method to round the battery level to the nearest whole number.

Simple logic is used to determine the color of the battery level bar based on the battery level. If the battery level is greater than 20%, the bar will be green, otherwise, it will be red.

We also show the charging icon if the device is charging:

const ChargingIcon = () => (
    <svg className="absolute right-0 mr-[-6px] w-6 h-6 text-green-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M11 7L6 12h4v8l5-5h-4v-8z" />
  </svg>
);
Enter fullscreen mode Exit fullscreen mode

Now, let’s put it all together in the BatteryIndicator component:

import { useState, useEffect } from 'react';

// Initial battery info: battery level: 0-100, charging status: true/false, supported by the browser: true/false 
const initialBatteryInfo = { level: 12, charging: true, supported: true };

export function BatteryIndicator() {
  const [batteryInfo, setBatteryInfo] = useState(initialBatteryInfo);

  // Update the battery info
  const updateBatteryInfo = (battery) => {
    setBatteryInfo({ level: battery.level * 100, charging: battery.charging, supported: true });
  };

  useEffect(() => {
    // Check if the browser supports the Battery Status API and setup the event listeners
    const checkBatteryAPIAndSetup = async () => {
      if (navigator.getBattery) {
        try {
          // Get the battery status
          const battery = await navigator.getBattery();
          updateBatteryInfo(battery);

          // Setup the event listeners for the battery status changes
          battery.addEventListener('chargingchange', () => updateBatteryInfo(battery));
          battery.addEventListener('levelchange', () => updateBatteryInfo(battery));
        } catch (error) {
          console.error('Battery status is not supported.');
          setBatteryInfo((prev) => ({ ...prev, supported: false }));
        }
      } else {
        console.error('Battery status is not supported.');
        setBatteryInfo((prev) => ({ ...prev, supported: false }));
      }
    };

    checkBatteryAPIAndSetup();
  }, []);

  return (
    <div className="flex items-center justify-center h-screen">
    <div className="text-center">
      {batteryInfo.supported ? (
        <div className="flex flex-col items-center justify-center space-y-2">
          <BatteryInfo batteryInfo={batteryInfo} />
        </div>
      ) : (
        <div className="p-4 rounded-md bg-gray-200 text-gray-700">
          Battery status is not supported in this browser.
        </div>
      )}
    </div>
  </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

So, our component is ready. Now, let’s import it into the App component, remove anything else, and see it in action.

import { BatteryIndicator } from './components/BatteryIndicator';

function App() {
  return (
    <div>
      <BatteryIndicator />
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Now, run the following command to start the development server and open the app in your browser.

npm run dev
Enter fullscreen mode Exit fullscreen mode

Open localhost:5173 in your browser. You should see the battery indicator component showing the current battery level and whether your device is charging.

If your device is charging you should see a charging icon on the right side of the battery level bar.

Green battery

If the battery level is less than 20% the battery level bar will be red:

Red battery

If the battery status is not supported in your browser, you should see a message saying “Battery status is not supported in this browser.”

Battery status is not supported in this browser message

That’s it! You’ve created a battery indicator component using React. It’s a fun project that works only in Chrome and other Chromium-based browsers like Edge. It’s not practical, but it’s a fun way to learn about the Battery Status API and how to use it in a React app.

References

I’m always looking to meet new people in tech. Feel free to connect with me on LinkedIn!

Top comments (3)

Collapse
 
fpaghar profile image
Fatemeh Paghar

It was new and is such a cool tutorial! Building a battery indicator with React sounds like a fun project to try out. It's great to see how you've laid out the steps clearly, from setting up the project with Vite to implementing the battery info logic using useState and useEffect hooks. While it's a bummer that the battery status API isn't supported in all browsers, it's still a neat way to learn about React and experiment with browser APIs. Thanks for sharing this fun project! for me.

Collapse
 
alexefimenko profile image
Alex

Thank you! I'm glad you liked it. I hope you find it useful.

Collapse
 
yuvrajsoneja2004 profile image
Yuvraj Soneja

kakus