A warm overlay that protects your users' eyes at night. One line of code. Works with Vanilla JS, React, and Next.js.
One function call. No plugins, no build config changes, no CSS imports.
pointer-events: none means clicks, modals, forms, and scrolling all work perfectly.
Zero runtime dependencies. TypeScript-first with full type exports.
Enable at 19:00, disable at 07:00. Custom timezones supported.
Optionally save state to localStorage so users don't have to re-enable each visit.
Respects prefers-reduced-motion. SSR-safe — no DOM access on the server.
import { createFlux } from '@andrewbro/luxify';
const flux = createFlux({
intensity: 0.25, // 0–1, how warm/dark the overlay is
color: '#ffb45c', // any valid CSS color
autoEnable: true, // enable immediately
persist: true // remember state in localStorage
});
// Control it programmatically
flux.enable();
flux.disable();
flux.toggle();
flux.setIntensity(0.4);
flux.setColor('#ff9f43');
flux.destroy();
import { FluxProvider, FluxOverlay, useFlux } from '@andrewbro/luxify/react';
function App() {
return (
<FluxProvider options={{ persist: true }}>
<FluxOverlay intensity={0.25} color="#ffb45c" />
<Page />
</FluxProvider>
);
}
function Page() {
const { toggle, setIntensity } = useFlux();
return (
<div>
<button onClick={toggle}>Toggle night mode</button>
<button onClick={() => setIntensity(0.35)}>Make it warmer</button>
</div>
);
}
'use client';
import { FluxProvider, FluxOverlay } from '@andrewbro/luxify/react';
export function NightLightShell({ children }: { children: React.ReactNode }) {
return (
<FluxProvider options={{ persist: true }}>
<FluxOverlay
intensity={0.22}
color="#ffb76b"
schedule={{ from: '19:00', to: '07:00', timeZone: 'Europe/Warsaw' }}
/>
{children}
</FluxProvider>
);
}
// In layout.tsx
export default function RootLayout({ children }) {
return (
<html>
<body>
<NightLightShell>{children}</NightLightShell>
</body>
</html>
);
}
// Enable from 19:00 to 07:00 automatically
createFlux({
schedule: {
from: '19:00',
to: '07:00',
timeZone: 'America/New_York' // optional, defaults to browser TZ
}
});
// Or use a fully custom callback
createFlux({
shouldEnable: ({ hour }) => hour >= 19 || hour < 7
});
// Combine with React
<FluxOverlay
schedule={{ from: '20:00', to: '06:00' }}
intensity={0.3}
/>
| Option | Type | Default | Description |
|---|---|---|---|
intensity |
number | 0.22 | Overlay opacity, 0–1 |
color |
string | '#ffb76b' | Any valid CSS color |
autoEnable |
boolean | false | Enable overlay on creation |
persist |
boolean | false | Save state to localStorage |
schedule |
{ from, to, timeZone? } | — | Auto-enable between two times (HH:MM) |
shouldEnable |
(ctx) => boolean | — | Custom enable logic callback |
zIndex |
number | 2147483646 | CSS z-index of the overlay |
transitionDuration |
number | 240 | Fade transition in ms |
respectReducedMotion |
boolean | true | Disable transitions for users who prefer reduced motion |
id |
string | 'luxify-overlay' | DOM element ID — reused across instances |
storageKey |
string | 'luxify' | localStorage key for persisted state |
| Method | Returns | Description |
|---|---|---|
enable() | void | Show the overlay |
disable() | void | Hide the overlay |
toggle() | void | Toggle visibility |
setIntensity(value) | void | Update opacity (0–1) |
setColor(color) | void | Update overlay color |
isEnabled() | boolean | Current visibility state |
getState() | FluxState | Returns { enabled, intensity, color } |
update(options) | void | Update multiple options at once |
destroy() | void | Remove overlay from DOM and stop scheduler |