Battery Indicator — Free CSS Battery Level HTML JS Snippet

Battery Indicator · Animations · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Pure CSS battery
Bordered body plus a cap nub — no images or icon font.
Percentage fill
Charge maps directly to the fill div's width value.
Color thresholds
Green, amber, and red states toggled in one paint() function.
Smooth transitions
Width and color animate with a cubic-bezier ease.
Charging mode
Bolt icon, pulsing fill, and a slow creep toward 100%.
No timer leaks
The charging interval is cleared the moment it stops.
Readable label
Centered percentage with a shadow over any fill color.
No dependency
Pure HTML/CSS/JS, ready to drop into any status bar.

About this UI Snippet

Battery Indicator — Animated Charge Level Widget

Screenshot of the Battery Indicator snippet rendered live

A battery indicator shows a device's charge as a familiar battery icon that fills and changes color — the control you see in status bars, IoT dashboards, EV apps, and laptop settings. This snippet builds one entirely from HTML, CSS, and vanilla JavaScript: a battery shell with a cap, a fill bar that animates between levels, color thresholds, and a charging mode with an animated bolt that slowly tops the battery up. No images, no SVG sprite sheet, no dependency.

The battery shape in pure CSS

The casing is a bordered rounded rectangle (.bat-body) with a small separate nub (.bat-cap) sitting against its right edge — together they read instantly as a battery. The fill is an absolutely-positioned inner div whose width is a percentage, so the charge level maps directly to a single CSS value. overflow:hidden on the body clips the fill to the rounded corners cleanly.

Color thresholds

Charge level drives three states via class toggles: at or below 12% the shell gets .crit (red), between 13–30% it gets .low (amber), and above that it stays green. The thresholds live in one paint() function with classList.toggle(name, condition), so the color logic is declarative — change the numbers in one place and both the bar and any themed elements follow.

Smooth level transitions

The fill's width and background are transitioned with a cubic-bezier ease, so dragging the slider or stepping the level animates fluidly rather than jumping. The percentage label is centered over the bar with a text shadow so it stays readable against both the dark empty track and the bright fill.

Charging mode

Toggling charge adds a .charging class that fades in a lightning-bolt SVG (hiding the percentage), runs a gentle batPulse opacity keyframe on the fill, and starts a setInterval that increments the level by 1% every 420ms until it reaches 100% — a believable "topping up" animation. Stopping charging clears the interval immediately so no timer leaks.

Wiring to real power data

Replace the slider with a real source: the browser navigator.getBattery() API exposes level and charging, or you can feed values from a device over WebSocket. Call paint() whenever the value changes; because all rendering is centralized there, the indicator stays a thin, stateless view over whatever charge number you give it.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You don't have to trace the threshold and timer logic by hand to get the full picture here. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly why the crit and low classes are computed with classList.toggle and boolean conditions rather than separate if/else branches, or what would happen to the charging interval if the toggle button were clicked rapidly. The same assistant is useful for optimizing it — asking whether the setInterval-based creep should be replaced with a requestAnimationFrame-driven tween for smoother visual pacing, or whether paint() is doing more DOM writes than necessary on every input event. It's also a fast way to extend the widget: ask it to wire it up to the real navigator.getBattery() API, add a low-battery pulse warning, or support multiple battery indicators on one page sharing a single charging timer. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build an animated "battery indicator" in plain HTML, CSS, and JavaScript using only div elements for the battery shape (no images, no icon fonts, no SVG battery outline) plus one inline SVG for the charging bolt.

Requirements:
- A battery shell made from a bordered, rounded rectangle body plus a small separate rectangular nub positioned against its right edge to read as the battery terminal.
- An inner fill element whose width is set as a percentage matching the current charge level, clipped to the body's rounded corners with overflow hidden, and animated with a CSS transition on both width and background-color so level changes ease smoothly rather than jumping.
- Three color states driven purely by numeric thresholds: green above 30%, amber between 13% and 30% inclusive, and red at 12% or below, toggled with classList.toggle calls rather than separate conditional blocks.
- A range input slider that drives the level in real time on its input event, updating both the fill width and a centered percentage label with a readable text-shadow.
- A "toggle charging" button that, when active, fades in a lightning-bolt icon centered over the battery (hiding the percentage label), runs a continuous subtle pulse animation on the fill, and starts an interval that increments the level by 1% at a fixed short delay until it reaches 100%, at which point the interval must stop itself.
- Clicking the charging button again while charging must immediately clear the running interval so no timer keeps firing in the background.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA battery shell renders with a fill bar and a percentage label.
  2. 2
    Drag the level sliderThe fill width animates and the percentage updates as you move it.
  3. 3
    Watch the color changeBelow 30% the fill turns amber, below 12% it turns red.
  4. 4
    Toggle chargingA lightning bolt appears and the bar pulses while the level creeps up.
  5. 5
    Let it reach fullCharging stops cleanly at 100% and the interval is cleared.
  6. 6
    Feed real dataReplace the slider with navigator.getBattery() and call paint().

Real-world uses

Common Use Cases

Device dashboards
Show charge beside a signal bars meter in a status row.
IoT and hardware UIs
Render live battery from a sensor next to a gauge chart.
Quota and usage views
Reuse the fill pattern for a quota usage meter.
EV and energy apps
Visualize charge state alongside a radial bar chart.
Status indicators
Pair with a status pill for device health at a glance.
Learning CSS shapes
A reference for building icons from borders and percentages.

Got questions?

Frequently Asked Questions

The body is a div with a thick border and rounded corners, and the terminal is a separate small div (the cap) placed against its right edge. The colored fill is an inner div with a percentage width, and overflow:hidden on the body clips it to the rounded corners. The whole icon is three divs and no graphics.

The paint() function calls classList.toggle('crit', level <= 12) and classList.toggle('low', level > 12 && level <= 30). Those classes change the fill background to red or amber; above 30% neither class applies and it stays green. Adjusting the breakpoints is a one-line change.

A .charging class fades in a bolt SVG, hides the percentage, and runs a pulsing opacity animation on the fill. A setInterval then raises the level by 1% every 420ms until 100%, simulating a real charge. Toggling charging off clears the interval immediately, so there are no leftover timers.

Yes. The browser navigator.getBattery() API returns a promise with level (0–1) and charging fields plus change events. Multiply level by 100, set the slider or call paint() directly, and toggle the charging class from the API's charging value. Any live source — WebSocket, polling — works the same way.

Keep the level and charging flag in state and bind the fill width to a style with the percentage. Move the creep-up setInterval into an effect (useEffect, onMounted, or ngOnInit) and clear it on cleanup to avoid leaks. In Tailwind, set the fill width with an inline style and switch the green/amber/red background via conditional classes.