expressive-code / expressive-code

A text marking & annotation engine for presenting source code on the web.

Home Page:https://expressive-code.com/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to work with automatic `system` theme detection without `useDarkModeMediaQuery`

diploidal opened this issue · comments

Hey 👋

I'm digging through the documentation and I'm stuck on handling the theme selection for my Astro website.

Current Setup:

I have three themes available: light, dark, and system. I apply these themes based on user selection using the data-theme attribute html[data-theme="light/dark/system"].

The Problem:

Everything works perfectly when users choose "light" or "dark" themes. However, when they select the "system" theme, which relies on the @media (prefers-color-scheme:...) media query, the theme isn't applied correctly to specific elements like code blocks.

Scenario:

  1. User enters the website (defaulting to "system")
  2. User visits a blog post with code blocks (rendered with "light" theme due to missing system theme handling).
  3. User switches to "dark" theme, forcing dark mode across the website (including code blocks) - which is good
  4. User switches to "light" theme (code blocks render light theme) - which is good
  5. User returns to "system" theme (their system is dark mode) and the entire page goes dark while code blocks remain light - which is wrong

Possible Cause:

I believe the code blocks aren't receiving the updated theme information when the "system" theme is selected. They might be relying on a previously set data-theme value.

Additional

  • I'm using data-theme to maintain theme consistency across the website.
  • useDarkModeMediaQuery is set to false to avoid forcing dark code blocks when the user chooses "light" theme, even if their system is dark.
  • my astro.config.ts configuration is provided below
    expressiveCode({
      plugins: [pluginLineNumbers()],
      themes: ['github-light', "github-dark"],
      themeCssSelector: (theme) => {
        if (theme.type === 'light') return `[data-theme='light']`;

        return `[data-theme='dark']`;
      },
      useDarkModeMediaQuery: false,
      defaultProps: {
        wrap: true,
        showLineNumbers: true,
        overridesByLang: {
          'bash': {
            showLineNumbers: false,
          },
        },
      },
    })

The Challenge:

I want to achieve two things:

  • Allow users to "force" light or dark mode for the entire
  • Have the "system" theme determine the theme for code blocks based on the user's system preference (at the same time not forcing it by useDarkModeMediaQuery so when dark system theme is used it updates while switching to "forced" light. useDarkModeMediaQuery simply overrides any user selected theme in favor of @media.

I would like to avoid turning off the "system" theme selection. 😅

Is there any way to determine theme selection within themeCssSelector for data-theme="system" variant ?

I hope this explanation is clear. Any suggestions on how to achieve this functionality would be greatly appreciated!

Hello! 👋 Thank you for this clear explanation of your use case!

You don't need to turn useDarkModeMediaQuery off to achieve what you want. This feature is well capable of co-existing with manual theme overrides using the html[data-theme] attribute.

The only change you probably need to make to your setup after re-enabling useDarkModeMediaQuery is removing the data-theme from the html element when the system theme should be displayed.

So, in your own theme switcher code, never set data-theme="system", but remove the attribute instead in this case to allow auto-selection. Basically, the automatic selection based on the user's system-wide preference is the default behavior, and manual overrides of the theme are possible by setting data-theme.

Ohhh I get it now.

And now everything works flawlessly. I've tried to keep data-theme="system' attribute in order to keep other things working 😃 and the theme is being detected perfectly for the code blocks.

useDarkModeMediaQuery set to true works perfectly. 😃

Thank You very much for ⚡blazingly fast⚡ support 😃!