If you’ve already spun up an EmDash instance, you’ve seen the dark mode toggle in the admin panel. It works. But that’s the surface. The real power? How EmDash handles dark mode at the theme level, how you override it per user, and how you can push custom schemes without touching core files. Let’s skip the basics and get into the non-obvious details.
The Built-in Toggle Is Just the Start
Every EmDash site ships with a system‑aware dark mode toggle. It’s in the admin header – click it, and the UI flips. The front‑end theme inherits the same preference via CSS custom properties. But here’s what most people miss: that toggle sets a cookie (emdash-themecode) and a data-themecode attribute on the code element. Your theme’s CSS uses those hooks. You’re not locked into a binary light/dark choice – the data-themecode attribute can hold any value you define.
The toggle is just the door. What you do behind it is up to you.
To see what values are available, inspect the code tag after toggling. You’ll get lightcode or darkcode. But in your Astro components, you can listen for changes and even enforce a specific theme per page or per content type.
Customizing the Color Palette Without a Plugin
EmDash themes are built on Astro. Dark mode colors are defined in CSS variables inside your theme’s src/styles/code directory. The default variables look something like:
“`css
:root[data-theme=”dark”] {
–color-bg: #1a1a2e;
–color-text: #e0e0e0;
–color-primary: #7c3aed;
/ … /
}
“`
You don’t need a plugin to change these. Override them in your own theme’s global CSS. The cascade works exactly as you’d expect. Want a warmer dark mode? Swap --color-bgcode to a charcoal and --color-textcode to a soft beige. Want accent colors that shift with the theme? Use the same data-themecode attribute inside your component scoped styles.
One non‑obvious trick: you can define multiple dark variants. Set data-theme="dark-blue"code or data-theme="dark-contrast"code and write corresponding CSS. Then conditionally apply them using a small script in your layout. This gives you per‑section theming – think a dashboard area with high contrast and a blog area with subdued tones.
User Preference vs. Global Override
The admin panel respects the user’s system preference by default. But you might want to force a theme for all visitors, or let logged‑in users choose a permanent preference. EmDash doesn’t ship a built‑in UI for per‑user theme locking – but you can build one with a few lines.
Here’s the pattern:
- Add a custom field to your user content type (e.g.,
theme_preferencecode) using EmDash’s content type builder in the admin. - In your Astro layout, check the user’s session and read that field.
- Set the
data-themecode attribute accordingly.
The Astro middleware or an API endpoint can handle the logic. This keeps the preference server‑side, so it persists across devices. The toggle in the admin still works – it just overrides the server value for that session.
Comparison of Customization Approaches
| Method | Scope | Effort | Persistence | Best for |
|---|---|---|---|---|
| Admin toggle (built‑in) | Entire session per browser | Zero | Cookie, lost on clear | Quick testing, temporary use |
| CSS variable overrides in theme | Global for all visitors | Low (edit CSS file) | Permanent in theme code | Brand‑consistent dark mode |
| Per‑user field + server logic | Per logged‑in user | Medium (custom field + middleware) | Database, cross‑device | Membership sites, dashboards |
| Plugin‑based theme switcher (future) | Plugin sandbox with capabilities | High (write plugin) | Via plugin manifest | Third‑party integrations, A/B testing |
Edge Case: Admin Dark Mode vs. Front‑End Dark Mode
EmDash separates admin and front‑end themes. The admin always uses its own dark mode CSS – you cannot change that without forking the admin UI (not recommended). But the front‑end theme is yours to control. If you want the admin to stay light while the front‑end goes dark, you can. Just don’t set the global data-themecode in your front‑end layout – use a scoped class instead. The admin panel ignores that class because it runs in a different iframe context.
What Most People Miss: The prefers-color-scheme Media Query
EmDash’s default theme already respects prefers-color-schemecode. But you can refine it. For example, you might want the admin to always follow the system, while the front‑end respects a user‑selected preference. To do that, remove the data-themecode override from your front‑end layout and rely on the media query alone in your CSS. Then add a manual toggle that sets a class on code instead of code. That way the admin’s code attribute stays untouched, and your front‑end theme can be controlled independently.
Forward‑Looking: Theming as a Plugin Capability
EmDash’s plugin sandbox opens a door most CMSs don’t have. A plugin could declare a capability like theme:customizecode and be granted write access only to CSS variables – not to the database or filesystem. That means you could distribute a dark mode customization pack as a sandboxed plugin. It would alter the color palette without ever touching your core theme files. That’s a level of isolation WordPress plugins can’t offer. Expect third‑party theme tweakers to appear once the ecosystem matures.
For now, the built‑in approach – CSS variables, user fields, and a small middleware script – is more than enough to bend EmDash’s dark mode to your will. The toggle is just the door. What you do behind it is up to you.
- How do I customize dark mode colors in EmDash?Override CSS variables like --color-bg and --color-text in your theme's global CSS using the data-theme attribute.
- Can I set a permanent dark mode preference for logged-in users?Yes, add a custom field to the user content type, then read it in your Astro layout to set the data-theme attribute.