Low Battery Guard

Before a long upload, export or call, compares battery runway with the task's length and offers to start once plugged in.

StopsUpload died on a flat battery

Installation

pnpm dlx shadcn@latest add https://bollard-ui.vercel.app/r/low-battery-guard.json

The files land in your project. They're yours to edit.

Usage

low-battery-guard-usage.tsx
import { LowBatteryGuard } from "@/components/ui/low-battery-guard"

{!exporting && <LowBatteryGuard task="the export" minutes={45} battery={battery} onProceed={() => setExporting(true)} />

What it catches

  • Task longer than the battery's remaining runway
  • Battery already low before starting
  • Start when plugged in: runs the task once a charger connects
  • Silent when the task fits

Props

LowBatteryGuard props
PropTypeDefault
task* (required)

What the user is about to start, e.g. "the export".

string—
minutes* (required)

How long the task usually takes, in minutes.

number—
battery

Override the browser reading (tests, native shells, SSR hydration).

BatteryReading—
onProceed

Start the task. Enables "Start anyway" and "Start when plugged in".

() => void—
fallback

Shown when this browser can't read the battery (Safari, Firefox). Nothing by default.

React.ReactNodenull
hideAfter

How long "Charging · safe to start" stays after plugging in, in ms.

number3000
shortTitle

Templates: `{task}` (lower case reads best, e.g. "the export"), `{level}`, `{runway}`, `{duration}` are filled in.

string"Battery will run out before {task} finishes"
tightTitle

Title when the runway is close to the task's length.

string"Battery is cutting it close for {task}"
lowTitle

Title when the battery won't last.

string"Battery at {level} and not charging"
chargingTitle

Title while charging.

string"Charging · safe to start {task}"
startedTitle

Title after the task starts on plug-in.

string"Charging · {task} started"
armedTitle

Title while waiting for a charger.

string"Plug in and {task} starts by itself"
detailText

Detail line under the title.

string"{level} lasts about {runway}, {task} needs about {durati…
lowDetailText

Detail line when the battery won't last.

string"Plug in to be safe: {task} needs about {duration}"
runwayLabel

Label for the battery runway.

string"Battery ~{runway}"
durationLabel

Label for the task's length.

string"Done in ~{duration}"
startWhenPluggedLabel

Button text to start once plugged in.

string"Start when plugged in"
startAnywayLabel

Button text to start now.

string"Start anyway"
cancelLabel

Button text to stop waiting.

string"Cancel"

* required. Also accepts the native props of <div> (className, aria-*, data-*…), passed through to it.

Accessibility

  • Banner is role=status
  • Runway bar is role=img with an aria-label giving runway and duration
  • Pulse animation is motion-safe only; icons are aria-hidden

Only what the source does. Test with your own screen reader and content before shipping.

Limitations

  • The Battery Status API is missing in Safari and Firefox; then it uses your fallback
  • Runway is an estimate from current drain
  • Doesn't pause or resume the task itself

What it stops

Upload died on a flat battery

Also known as

low battery · battery api · upload · online exam · export · plug in · charger · mobile

Field type

Dependencies

Pairs well with