Skip to content

Theming

Acopl UI ships with dark mode as default and a complete light mode variant. Theme switching is controlled via the data-theme attribute on the <html> element.

<!-- Dark mode (default) -->
<html data-theme="dark">
<!-- Light mode -->
<html data-theme="light">

All components use semantic CSS Custom Properties (--ac-*) that automatically change value when the theme changes. You never need to update components individually.

Components are written like this:

.ac-button--primary {
background-color: var(--ac-action); /* changes per theme */
color: #fff;
}

The --ac-action token resolves to:

  • dark: #F97316 (Safety Orange)
  • light: #EA580C (Orange-600, higher contrast)
TokenDark valueLight valuePurpose
--ac-bg#020617#F8FAFCPage background
--ac-surface#0F172A#FFFFFFCards, panels
--ac-surface-2#1E293B#F1F5F9Elevated surfaces
--ac-text#E2E8F0#1E293BPrimary text
--ac-text-muted#94A3B8#64748BSecondary text
--ac-text-subtle#475569#94A3B8Disabled, placeholders
--ac-borderrgba(255,255,255,0.1)rgba(0,0,0,0.1)Default borders
--ac-border-strongrgba(255,255,255,0.2)rgba(0,0,0,0.2)Hover borders
--ac-primary#2563EB#2563EBBlue — trust
--ac-action#F97316#EA580COrange — CTAs
--ac-success#10B981#059669Green — success
--ac-danger#EF4444#EF4444Red — errors
import { ThemeManager } from 'https://ui.acopl.ar/v2.0.0/acopl-ui.js';
// Initialize (reads localStorage → prefers-color-scheme → default)
ThemeManager.init(); // call once on page load
ThemeManager.init('light'); // force light as default
// Control
ThemeManager.toggle(); // switch between dark/light
ThemeManager.set('light'); // force a specific theme
ThemeManager.get(); // → 'dark' | 'light'
// Helpers
ThemeManager.isDark(); // → boolean
ThemeManager.isLight(); // → boolean
ThemeManager.clearOverride(); // remove manual override, follow system
// Subscribe to changes
const unsubscribe = ThemeManager.onChange((theme) => {
console.log('Theme changed to:', theme);
});
unsubscribe(); // stop listening

Without this inline script, the page flashes the wrong theme for ~100ms while the JS bundle loads. Add this before your CSS link:

<head>
<script>
(function(){
var t = localStorage.getItem('ac-theme') ||
(window.matchMedia('(prefers-color-scheme:light)').matches ? 'light' : 'dark');
document.documentElement.setAttribute('data-theme', t);
})();
</script>
<link rel="stylesheet" href="https://ui.acopl.ar/v2.0.0/acopl-ui.css">
</head>

You can use the semantic tokens directly in your project’s CSS:

.my-panel {
background: var(--ac-surface);
border: 1px solid var(--ac-border);
color: var(--ac-text);
}
.my-panel:hover {
border-color: var(--ac-border-strong);
}
.my-cta {
background: var(--ac-action);
color: #fff;
}

These will automatically adapt to dark/light mode without any extra code.

Projects still using --color-brand-* tokens from v1.x continue to work — they are aliased to the new semantic tokens:

/* These still work in v2 */
var(--color-brand-base) → var(--ac-bg)
var(--color-brand-surface) → var(--ac-surface)
var(--color-brand-blue) → var(--ac-primary)
var(--color-brand-orange) → var(--ac-action)
var(--color-brand-green) → var(--ac-success)
var(--color-brand-border) → var(--ac-border)
/* NEW in v2 — previously missing, now available */
var(--color-text) → var(--ac-text)
var(--color-text-secondary) → var(--ac-text-muted)
var(--color-surface) → var(--ac-surface)
var(--color-border) → var(--ac-border)
var(--color-primary) → var(--ac-primary)