{"id":98030,"date":"2026-10-07T00:38:00","date_gmt":"2026-10-07T04:38:00","guid":{"rendered":"https:\/\/overcentral.com\/en\/?p=98030"},"modified":"2026-09-29T07:56:30","modified_gmt":"2026-09-29T11:56:30","slug":"emdash-dark-mode-customization-98030","status":"publish","type":"post","link":"https:\/\/overcentral.com\/en\/emdash-dark-mode-customization-98030\/","title":{"rendered":"EmDash Dark Mode: Enable, Customize, and Extend"},"content":{"rendered":"<p>If you\u2019ve already spun up an EmDash instance, you\u2019ve seen the dark mode toggle in the admin panel. It works. But that\u2019s 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\u2019s skip the basics and get into the non-obvious details.<\/p>\n<h2>The Built-in Toggle Is Just the Start<\/h2>\n<p>Every EmDash site ships with a system\u2011aware dark mode toggle. It\u2019s in the admin header \u2013 click it, and the UI flips. The front\u2011end theme inherits the same preference via CSS custom properties. But here\u2019s what most people miss: that toggle sets a cookie (<code>emdash-theme<\/code>code) and a <code>data-theme<\/code>code attribute on the <code><\/code>code element. Your theme\u2019s CSS uses those hooks. You\u2019re not locked into a binary light\/dark <a href=\"https:\/\/overcentral.com\/en\/ichra-choice-arrangements-label-97925\/\" title=\"ICHRA Gets CHOICE Arrangements Label from CMS, SBA\" data-iacss-internal=\"1\">choice<\/a> \u2013 the <code>data-theme<\/code>code attribute can hold any value you define.<\/p>\n<p>To see what values are available, inspect the <code><\/code>code tag after toggling. You\u2019ll get <code>light<\/code>code or <code>dark<\/code>code. But in your Astro components, you can listen for changes and even enforce a specific theme per page or per content type.<\/p>\n<h2>Customizing the Color Palette Without a Plugin<\/h2>\n<p>EmDash themes are built on Astro. Dark mode colors are defined in CSS variables inside your theme\u2019s <code>src\/styles\/<\/code>code directory. The default variables look something like:<\/p>\n<p>&#8220;`css<\/p>\n<p>:root[data-theme=&#8221;dark&#8221;] {<\/p>\n<p>  &#8211;color-bg: #1a1a2e;<\/p>\n<p>  &#8211;color-text: #e0e0e0;<\/p>\n<p>  &#8211;color-primary: #7c3aed;<\/p>\n<p>  \/<em> \u2026 <\/em>\/<\/p>\n<p>}<\/p>\n<p>&#8220;`<\/p>\n<p>You don\u2019t need a plugin to change these. Override them in your own theme\u2019s global CSS. The cascade works exactly as you\u2019d expect. Want a warmer dark mode? Swap <code>--color-bg<\/code>code to a charcoal and <code>--color-text<\/code>code to a soft beige. Want accent colors that shift with the theme? Use the same <code>data-theme<\/code>code attribute inside your component scoped styles.<\/p>\n<p>One non\u2011obvious trick: you can define multiple dark variants. Set <code>data-theme=\"dark-blue\"<\/code>code or <code>data-theme=\"dark-contrast\"<\/code>code and write corresponding CSS. Then conditionally apply them using a small script in your layout. This gives you per\u2011section theming \u2013 think a dashboard area with high contrast and a blog area with subdued tones.<\/p>\n<h2>User Preference vs. Global Override<\/h2>\n<p>The admin panel respects the user\u2019s system preference by default. But you might want to force a theme for all visitors, or let logged\u2011in users choose a permanent preference. EmDash doesn\u2019t ship a built\u2011in UI for per\u2011user theme locking \u2013 but you can build one with a few lines.<\/p>\n<p>Here\u2019s the pattern:<\/p>\n<ol>\n<li>Add a custom field to your user content type (e.g., <code>theme_preference<\/code>code) using EmDash\u2019s content type builder in the admin.<\/li>\n<li>In your Astro layout, check the user\u2019s session and read that field.<\/li>\n<li>Set the <code>data-theme<\/code>code attribute accordingly.<\/li>\n<\/ol>\n<p>The Astro middleware or an API endpoint can handle the logic. This keeps the preference server\u2011side, so it persists across devices. The toggle in the admin still works \u2013 it just overrides the server value for that session.<\/p>\n<h2>Comparison of Customization Approaches<\/h2>\n<table class=\"mw-table\">\n<thead>\n<tr>\n<th>Method<\/th>\n<th>Scope<\/th>\n<th>Effort<\/th>\n<th>Persistence<\/th>\n<th>Best for<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Admin toggle (built\u2011in)<\/td>\n<td>Entire session per browser<\/td>\n<td>Zero<\/td>\n<td>Cookie, lost on clear<\/td>\n<td>Quick testing, temporary use<\/td>\n<\/tr>\n<tr>\n<td>CSS variable overrides in theme<\/td>\n<td>Global for all visitors<\/td>\n<td>Low (edit CSS file)<\/td>\n<td>Permanent in theme code<\/td>\n<td>Brand\u2011consistent dark mode<\/td>\n<\/tr>\n<tr>\n<td>Per\u2011user field + server logic<\/td>\n<td>Per logged\u2011in user<\/td>\n<td>Medium (custom field + middleware)<\/td>\n<td>Database, cross\u2011device<\/td>\n<td>Membership sites, dashboards<\/td>\n<\/tr>\n<tr>\n<td>Plugin\u2011based theme switcher (future)<\/td>\n<td>Plugin sandbox with capabilities<\/td>\n<td>High (write plugin)<\/td>\n<td>Via plugin manifest<\/td>\n<td>Third\u2011party integrations, A\/B testing<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>Edge Case: Admin Dark Mode vs. Front\u2011End Dark Mode<\/h2>\n<p>EmDash separates admin and front\u2011end themes. The admin always uses its own dark mode CSS \u2013 you cannot change that without forking the admin UI (not recommended). But the front\u2011end theme is yours to control. If you want the admin to stay light while the front\u2011end goes dark, you can. Just don\u2019t set the global <code>data-theme<\/code>code in your front\u2011end layout \u2013 use a scoped class instead. The admin panel ignores that class because it runs in a different iframe context.<\/p>\n<h2>What Most People Miss: The <code>prefers-color-scheme<\/code> Media Query<\/h2>\n<p>EmDash\u2019s default theme already respects <code>prefers-color-scheme<\/code>code. But you can refine it. For example, you might want the admin to always follow the system, while the front\u2011end respects a user\u2011selected preference. To do that, remove the <code>data-theme<\/code>code override from your front\u2011end layout and rely on the media query alone in your CSS. Then add a manual toggle that sets a class on <code><\/code>code instead of <code><\/code>code. That way the admin\u2019s <code><\/code>code attribute stays untouched, and your front\u2011end theme can be controlled independently.<\/p>\n<h2>Forward\u2011Looking: Theming as a Plugin Capability<\/h2>\n<p>EmDash\u2019s plugin sandbox opens a door most CMSs don\u2019t have. A plugin could declare a capability like <code>theme:customize<\/code>code and be granted write access only to CSS variables \u2013 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\u2019s a level of isolation WordPress plugins can\u2019t offer. Expect third\u2011party theme tweakers to appear once the ecosystem matures.<\/p>\n<p>For now, the built\u2011in approach \u2013 CSS variables, user fields, and a small middleware script \u2013 is more than enough to bend EmDash\u2019s dark mode to your will. The toggle is just the door. What you do behind it is up to you.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you\u2019ve already spun up an EmDash instance, you\u2019ve seen the dark mode toggle in the admin panel. It works. But that\u2019s 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\u2019s skip [&hellip;]<\/p>\n","protected":false},"author":7,"featured_media":99334,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"fifu_image_url":"https:\/\/cards.overcentral.com\/cards\/en\/98030.png","fifu_image_alt":"EmDash Dark Mode: Enable, Customize, and Extend","footnotes":""},"categories":[31],"tags":[],"class_list":["post-98030","post","type-post","status-publish","format-standard","has-post-thumbnail","category-technology"],"fifu_image_url":"https:\/\/cards.overcentral.com\/cards\/en\/98030.png","fifu_image_alt":"EmDash Dark Mode: Enable, Customize, and Extend","_links":{"self":[{"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/posts\/98030","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/comments?post=98030"}],"version-history":[{"count":1,"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/posts\/98030\/revisions"}],"predecessor-version":[{"id":99335,"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/posts\/98030\/revisions\/99335"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/media\/99334"}],"wp:attachment":[{"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/media?parent=98030"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/categories?post=98030"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/tags?post=98030"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}