Env
@ailuracode/alpine-env
Browser environment magics in one package: connectivity, tab visibility, battery, and platform detection.
The root entrypoint stays focused on Alpine magics. The headless API lives under @ailuracode/alpine-env/controller.
Install
pnpm add @ailuracode/alpine-env @ailuracode/alpine-core alpinejsQuick start
import Alpine from "alpinejs";import env from "@ailuracode/alpine-env";
Alpine.plugin(env());Alpine.start();Magics
| Magic | Description |
|---|---|
$network |
Online / offline state |
$visibility |
Tab visibility (Page Visibility API) |
$battery |
Battery level and charging |
$platform |
OS and device detection |
Selective registration
Alpine.plugin(env({ battery: false, visibility: false }));Avoiding name collisions
If your application already owns one of the env magics ($network, $visibility, $battery, $platform) — or another toolkit plugin registers on one of those names — rename the integration surface without forking the helpers:
Alpine.plugin( env({ networkKey: "net", // → $net visibilityKey: "page", // → $page batteryKey: "power", // → $power platformKey: "os", // → $os }),);The exposed constants DEFAULT_ENV_NETWORK_KEY, DEFAULT_ENV_VISIBILITY_KEY, DEFAULT_ENV_BATTERY_KEY, and DEFAULT_ENV_PLATFORM_KEY keep the renames discoverable from TypeScript.
$network
Reactive connectivity from navigator.onLine.
| Property | Type | Description |
|---|---|---|
isOnline |
boolean |
true when online |
isOffline |
boolean |
true when offline |
<div x-show="$network.isOffline">You are offline</div>$visibility
Reactive tab visibility from the Page Visibility API.
| Property / method | Type | Description |
|---|---|---|
isVisible |
boolean |
Tab is visible |
isHidden |
boolean |
Tab is hidden |
state |
"visible" | "hidden" | "prerender" |
Raw visibility state |
is(state) |
(state) => boolean |
Compare current state |
<div x-show="$visibility.isHidden">Tab is in the background</div>$visibility is registered by @ailuracode/alpine-env. Pair with @ailuracode/alpine-attention when you also need wake lock or idle detection.
$battery
Reactive battery status when the Battery Status API is available.
| Property | Type | Description |
|---|---|---|
isAvailable |
boolean |
Battery Status API available in this browser |
level |
number | null |
Charge level 0–1 |
isCharging |
boolean |
Whether the device is charging |
chargingTime |
number | null |
Seconds until charged (null when unknown) |
dischargingTime |
number | null |
Seconds until empty (null when unknown) |
<span x-text="`${Math.round(($battery.level ?? 0) * 100)}%`"></span>$platform
Operating system and device flags from navigator.userAgent and related signals.
| Property | Type | Description |
|---|---|---|
name |
PlatformName |
"macos", "windows", "linux", "ios", "android", "chromeos", or "unknown" |
isMac |
boolean |
macOS |
isWindows |
boolean |
Windows |
isLinux |
boolean |
Linux desktop |
isIos |
boolean |
iOS (including iPadOS) |
isAndroid |
boolean |
Android |
isChromeos |
boolean |
ChromeOS |
is(platform) |
(platform) => boolean |
Compare against the detected platform |
<button x-show="$platform.isIos">Install on Home Screen</button>See Device detection for when to use env vs media.
Headless controller
Use the controller subpath when you want lifecycle-managed environment state without Alpine:
import { createEnv } from "@ailuracode/alpine-env/controller";
const env = createEnv();env.on("change", (detail) => { console.log(detail.network.isOnline);});EnvController is SSR-safe to construct, starts subscriptions in mount(), and removes listeners on destroy().
Root package no longer exports platform helpers or per-feature controllers. Import the controller subpath for headless usage and use the root package for Alpine integration only.
License
MIT
