Logo
Neura UI
Loading…
 Logo

Dark Mode

Learn how Neura handles dark mode and how to customize it

Overview

By default, Neura will handle the appearance of your application by adding a dark class to the html element depending on the user's system preference or selected appearance.
Neura includes a built-in theme switcher component that allows users to toggle between light, dark, and system preferences. The theme preference is automatically saved to localStorage and persists across page reloads. Theme changes animate with the View Transition API when the browser supports it.

Using the Theme Switcher

Neura provides a theme switcher component that you can add to your application:
blade
<neura::theme-switcher variant="dropdown" />
The theme switcher component supports multiple variants: dropdown , inline , stacked , and pullcord .

Animation Types

Theme changes use the browser View Transition API . Pick an effect with the animation prop on neura::theme-switcher , or set a kit-wide default via $theme.configure() . Unsupported browsers and prefers-reduced-motion fall back to an instant switch.
blade

circle

blur-circle

qr-scan

polygon

polygon-gradient

none

<neura::theme-switcher variant="inline" animation="circle" />
<neura::theme-switcher variant="inline" animation="blur-circle" />
<neura::theme-switcher variant="inline" animation="qr-scan" />
<neura::theme-switcher variant="inline" animation="polygon" />
<neura::theme-switcher variant="inline" animation="polygon-gradient" />
<neura::theme-switcher variant="inline" animation="none" />
Type Description
circle Expanding circle from the clicked control (default)
blur-circle Circle reveal with a soft blurred edge
qr-scan Horizontal scan line sweeping left to right
polygon Diagonal wipe (toward dark from top-left, toward light from bottom-right)
polygon-gradient Diagonal wipe with a soft gradient edge from the top-left
gif Reveal through a custom GIF mask — requires gifUrl via $theme.configure()
none Instant theme change with no animation
Configure defaults globally (animation type, duration, blur, GIF mask):
Blade
<div x-data x-init="$theme.configure({
    animationType: 'blur-circle',
    duration: 900,
    blurAmount: 4,
})">
    <neura::theme-switcher variant="inline" />
</div>


<div x-data x-init="$theme.configure({
    animationType: 'gif',
    gifUrl: 'https://example.com/mask.gif',
    duration: 2000,
})">
    <button type="button" @click="$theme.toggle($event)">Toggle</button>
</div>

PullCord

A ceiling pull-cord you can grab — the rope is a real Verlet simulation that hangs, swings, and settles. Pull past the detent to toggle the theme (fires mid-pull, like a real chain). Click and Enter work too.

Look up

The cord mounts with position: fixed at the top of the viewport. Try the live demo in the top-right of this page after enabling the example below — or drop the component into your layout.
blade
App chrome

Grab the knob hanging from the ceiling and pull — or click / press Enter on it.

<neura::theme-switcher variant="pullcord" />


<neura::theme-switcher
    variant="pullcord"
    :gravity="1250"
    :damping="0.94"
    :iterations="20"
    :stretch-max="26"
/>

<style>
:root {
    --nk-pullcord-top: 0px;
    --nk-pullcord-right: 7rem;
    --nk-pullcord-z: 50;
    --nk-pullcord-ink: rgba(127, 127, 127, 0.45);
}
</style>
Prop / CSS var Default Description
variant 'pullcord' Enables the hanging cord switcher
gravity 1250 Hang tension / fall speed
damping 0.94 Higher = snappier retract
iterations 20 Rope stiffness (constraint solver passes)
stretchMax 26 How deep you can pull past rest
noEntrance false Skip the drop-in entrance animation
--nk-pullcord-top 0px Anchor offset from the top
--nk-pullcord-right 7rem Distance from the right edge
--nk-pullcord-ink rgba(127,127,127,.45) Rope stroke colour

Alpine.js Theme Magic

Neura provides an Alpine.js magic property $theme that you can use in your components:
Blade
<button @click="$theme.setLight($event)">
    Light Mode
</button>

<button @click="$theme.setDark($event)">
    Dark Mode
</button>

<button @click="$theme.setSystem($event)">
    System Preference
</button>

<div x-show="$theme.isResolvedToDark">
    This content is only visible in dark mode
</div>
Pass $event so the View Transition expands from the control. Available methods and properties:
Method/Property Description
$theme.setLight($event?) Set theme to light mode
$theme.setDark($event?) Set theme to dark mode
$theme.setSystem($event?) Use system preference
$theme.toggle($event?) Toggle between light and dark
$theme.configure(options) Set kit-wide animation defaults (animationType , duration , blurAmount , gifUrl , …)
$theme.isResolvedToLight Check if currently in light mode
$theme.isResolvedToDark Check if currently in dark mode

Manual Theme Management

If you don't want Neura to handle theme management for you, you can remove the theme management from the JavaScript globals and handle the appearance of your application manually.
To disable automatic theme management, you can comment out or remove the theme initialization in your JavaScript files.

Custom Dark Mode Styles

Neura uses Tailwind's dark mode variant. You can customize dark mode styles using the dark: prefix:
Blade
<div class="bg-white dark:bg-neutral-900 text-neutral-900 dark:text-white">
    Content that adapts to theme
</div>