JavaScript & assets

How Atlas manages Alpine, the Atlas API, appearance and theme switching, and what to know when your application bundles its own Alpine.

Atlas JavaScript does four things: it provides an Alpine instance with the collapse plugin, registers the Alpine behaviours its components need (accordion, hamburger, tabs, swiper), exposes its API on window.Atlas, and wires up appearance (dark/light/system) and theme switching with localStorage persistence.

With Vite

Import Atlas in your application's entry point and start it:

import { Atlas } from '../../vendor/webreact/atlas/dist/atlas.js'

Atlas.start()

That is all an application without its own Alpine instance needs. Atlas imports Alpine, registers the collapse plugin, wires up its component behaviours, sets window.Alpine and window.Atlas, and starts Alpine when you call Atlas.start().

If your application bundles Alpine

Atlas is built to share: it reuses window.Alpine when it finds one, and starts Alpine only if nobody else has. Two details decide whether that works.

Your bundle must register the collapse plugin Atlas needs, before starting Alpine. A plugin registered after Alpine.start() never reaches DOM that Alpine has already processed. Atlas registers collapse when its bundle runs — if that happens after your Alpine.start(), x-collapse inside an accordion silently does nothing. Registering it yourself, before you start, fixes it:

import Alpine from 'alpinejs'
import collapse from '@alpinejs/collapse'

window.Alpine = Alpine

Alpine.plugin(collapse)

// Register any project-level plugins here, then start.
Alpine.start()

Then import Atlas after — it detects the existing window.Alpine, skips starting it, and registers its own behaviours:

import { Atlas } from '../../vendor/webreact/atlas/dist/atlas.js'

// Atlas sees window.Alpine, so Atlas.start() does not call Alpine.start() again.
Atlas.start()

Load order has to be the same in every environment. Importing Atlas from your own entry point, as above, keeps the order fixed regardless of build mode.

<x-docs.note tone="warning"> This site does both, on purpose. The documentation shell owns Alpine and imports the package bundle itself; the standalone preview pages use @atlasScripts, because they have no Alpine of their own. That way both documented paths stay exercised. </x-docs.note>

Atlas API

window.Atlas exposes an API for controlling Atlas at runtime:

// Appearance (dark / light / system)
Atlas.appearance = 'dark'     // set mode
Atlas.appearance              // read current mode
Atlas.dark                    // true when dark mode is active (read/write)

// Theme switching
Atlas.theme = 'corporate'     // switch theme (sets data-theme on <html>)
Atlas.theme                   // read current theme name

// Lifecycle
Atlas.start()                 // start Alpine and fire ready callbacks
Atlas.started                 // true after start() has been called
Atlas.ready(callback)         // run when Atlas starts; returns unsubscribe fn
Atlas.refresh(root?)          // re-run all ready callbacks (e.g. after navigation)

// Events
Atlas.on('appearance-changed', (detail) => { ... })   // subscribe
Atlas.dispatch('custom-event', { key: 'value' })       // dispatch

// Component registry
Atlas.register('swiper', 'hero', instance)
Atlas.get('swiper', 'hero')
Atlas.unregister('swiper', 'hero')

Alpine magic

Inside any Alpine component, $atlas gives access to the same API:

<div x-data>
    <button @click="$atlas.appearance = 'dark'">Dark mode</button>
    <span x-text="$atlas.dark ? 'Dark' : 'Light'"></span>
</div>

Appearance

The appearance feature manages dark/light/system mode with three moving parts:

  1. A reactive Atlas.appearance property that accepts 'light', 'dark' or 'system'.
  2. A media query listener that tracks prefers-color-scheme when the mode is system.
  3. localStorage persistence under atlas.appearance, so the choice survives page loads.

When the resolved mode is dark, Atlas adds the .dark class and data-appearance="dark" to <html>. When it is light, both are removed.

The @atlasAppearance directive — placed in <head> — applies the stored mode before the main bundle loads, preventing a flash of the wrong color scheme. It reads the appearance value from the published config as the default for first visits.

Configuration

Set the default in the published config:

// config/atlas.php
'appearance' => 'system', // 'system', 'light', or 'dark'

Theme switching

Atlas supports multiple themes through data-theme on <html>. Each theme is a CSS file scoped under [data-theme="name"] — see Scaffolding a theme in the theming guide.

Atlas.theme = 'corporate'    // applies [data-theme="corporate"]
Atlas.theme = ''             // reverts to the base theme

The active theme persists in localStorage under atlas.theme. The @atlasTheme directive applies the stored theme before the first paint.

Configuration

Set the default theme in the published config:

// config/atlas.php
'theme' => null, // null = base theme; 'corporate' = start with that theme

Livewire

Atlas listens for livewire:navigated and calls Atlas.refresh() automatically, so components re-initialise after Livewire page navigations without any extra wiring.

Swiper

The carousel reads its options from data-* attributes that the Blade component writes, so there is no per-instance JavaScript to author. The runtime initialises every carousel on the page once the DOM is ready, honours prefers-reduced-motion, and registers the Pagination, Navigation, A11y and Keyboard modules. See Swiper for the options.

Without Vite: asset routes

@atlasStyles and @atlasScripts serve files from the package's own dist directory through Laravel routes:

| Route | Content | | --- | --- | | /atlas/atlas.css | Vendor CSS (swiper, hamburgers) | | /atlas/atlas.js | ES module (development) | | /atlas/atlas.min.js | ES module (production) | | /atlas/atlas.csp.js | CSP-safe ES module (development) | | /atlas/atlas.csp.min.js | CSP-safe ES module (production) | | /atlas/atlas.umd.js | UMD bundle (classic script tag) | | /atlas/atlas.umd.min.js | UMD bundle (production) | | /atlas/atlas.umd.css | Standalone compiled CSS for UMD |

Each URL carries a content hash from the package's manifest, so a package upgrade busts the cache. Remember that @atlasStyles serves vendor CSS only — component styling comes from your Tailwind build, as described in Installation.

Content Security Policy

Both directives accept a nonce:

@atlasStyles(['nonce' => $nonce])
@atlasScripts(['nonce' => $nonce])
@atlasAppearance(['nonce' => $nonce])
@atlasTheme(['nonce' => $nonce])

For Vite builds, import dist/atlas.csp.js instead of dist/atlas.js to get an Alpine build that avoids eval():

import { Atlas } from '../../vendor/webreact/atlas/dist/atlas.csp.js'

Atlas.start()

Or enable CSP-safe mode in the config so @atlasScripts serves the CSP variant automatically:

// config/atlas.php
'csp_safe' => true,

Multisite and subdirectory installs

Set assets.base_url in the published config — a string or a closure — to prefix the asset URLs with an absolute origin.