The dark mode feature in Storybook is causing some trouble

Currently, I am utilizing storybook for my svelte + tailwind application and experimenting with implementing a dark mode toggle feature.

In my tailwind.config.js, I included the following:

module.exports = {
  darkMode: "class",

Additionally, I integrated this addon into Storybook: https://github.com/hipstersmoothie/storybook-dark-mode

Utilizing this configuration in .storybook/preview.js:

export const parameters = {
  darkMode: {
    darkClass: "dark",
    stylePreview: false,
  },

While inspecting the DOM of the Storybook iframe, I noticed that "dark" is indeed applied to the body. However, when implementing a component with the following HTML structure:

<div class="inline">
  <div class="w-8 h-8 bg-blue-500 dark:bg-green-500" />
</div>

The box consistently displays as blue. Suspecting PurgeCSS may be causing this issue, I attempted adding safelist: ["dark"] without success.

To further complicate matters, I tested another component:

<div class="inline">
  <div class="w-8 h-8 bg-blue-500 dark:bg-green-500" />
</div>
<div class="inline dark">
  <div class="w-8 h-8 bg-blue-500 dark:bg-green-500" />
</div>

Surprisingly, one of the boxes did change to green.

At this point, it's unclear whether the issue lies within svelte, storybook, tailwind, or the dark mode plugin for Storybook. Any insights or assistance would be greatly appreciated.

Answer β„–1

If you're having trouble with purgecss while watching for storybook, one solution could be to ignore it.

For my specific setup, I had to make a conditional adjustment in postcss.config.js to ensure storybook functioned correctly:

const isProduction =
  !process.env.ROLLUP_WATCH &&
  !process.env.LIVERELOAD &&
  process.env.NODE_ENV !== 'development'

module.exports = {
  plugins: [
    require('tailwindcss'),
    ...(isProduction ? [purgecss] : [])
  ]
};

In my .storybook/preview.js, I added the following code snippet:

export const parameters = {
  darkMode: {
    stylePreview: true,
    darkClass: 'dark',
    lightClass: 'light',
  }
}

The only issue I encountered after implementing this was the white text in dark mode, which I resolved by adding .dark { color: white; } to my CSS file.

Answer β„–2

Encountered a similar issue where the problem stemmed from defining a prefix of vc- within my tailwind.config.js file.

During the setup of the addon https://github.com/hipstersmoothie/storybook-dark-mode, I mistakenly used the class dark instead of vc-dark in .storybook/preview.js:

export const parameters = {
  darkMode: {
    dark: { ...themes.dark },
    light: { ...themes.light },
    darkClass: 'dark',
    stylePreview: true
  }
}

The correct implementation should have been:

export const parameters = {
  darkMode: {
    dark: { ...themes.dark },
    light: { ...themes.light },
    darkClass: 'vc-dark',
    stylePreview: true
  }
}

If there is a prefix specified in your tailwind.config.js file, be cautious as it might lead to similar complications for others experiencing this issue.

Despite using the prefix, you can still utilize the dark variant normally; just remember to incorporate the prefix when referencing class names post-variant:

<div class="vc-bg-blue-500 dark:vc-bg-green-500" />

Answer β„–3

One reason for this occurrence is that components are displayed within an iframe, and the storybook-dark-mode (SDM) feature only assigns the "dark" class to the body of the main document.

I confirmed this by inspecting and manually adding it. If you have configured darkMode: 'class' in your tailwind settings, you should observe it functioning as expected when you insert

<body class="dark">
inside the iframe. Consequently, wrapping it with a parent containing "dark" makes it work solely for that specific instance.

Initial Experiment

The question remains on how to extend this class assignment to the body of the iframe. According to SDM documentation, it suggests applying it to both the application and preview window, which does not appear to be happening in my case.

Interestingly, there exists an add-on known as storybook-tailwind-dark-mode (STDM) that appends "dark" to the <html> tag of the iframed document, offering some functionality; however, it requires a separate button. This enables rendering components in either dark or light mode independently from the application's dark mode setting.

Currently, this method is effective for me, but I am interested in exploring options where both functionalities can be achieved simultaneously.

For what it’s worth, prior to adopting Tailwind, we utilized a ThemeProvider from StyledComponents with useDarkMode() from SDM to propagate themes downwards to all StyledComponents (a process we are transitioning away from in favor of Tailwind). Finding a way to incorporate this would be beneficial.

Ultimate Solution

The preceding paragraph sparked an idea. Storybook provides decorators, essentially functions returning components. By enclosing our stories with HTML adorned with classes based on useDarkMode(), we foster the desired outcome.

Shown below is the implementation I settled on, delivering excellent results. A single button administering dark mode, dispensing with the necessity for additional tailwind-specific dependencies, while seamlessly integrating with my existing StyledComponent theming for yet-to-be-migrated components.

.storybook/theme.js

import React from 'react'
import { ThemeProvider } from 'styled-components'
import { themeV2, GlobalStylesV2 } from 'propritary-design-library'
import { useDarkMode } from 'storybook-dark-mode'
import '../src/index.css'

const ThemeDecorator = storyFn => {
  const mode = useDarkMode() ? 'dark' : 'light'

  return (
    <ThemeProvider theme={themeV2(mode)}>
      <section className={mode}>
        <GlobalStylesV2 />
        {storyFn()}
      </section>
    </ThemeProvider>
  )
}

export default ThemeDecorator

.storybook/preview.js

import { addDecorator } from '@storybook/react'
import ThemeDecorator from './theme'

addDecorator(ThemeDecorator)

export const parameters = {
  controls: {
    matchers: {
      color: /(background|color)$/i,
      date: /Date$/,
    },
  },
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Customizing ExtJS 4's CSS reset specifically for tailored HTML inside components

I am currently in the process of upgrading an existing application from Ext 3.x to 4. I have successfully enabled Ext's scoped reset CSS option to prevent Ext from applying its CSS reset to my entire application. However, I am now facing a new issue. ...

Attempting to synchronize the top row headings with the corresponding rows beneath

I can't seem to get the column heading aligned perfectly with the rows below it. The headings always appear slightly to the right. I've already tried adjusting the margin and removing overflow auto, but nothing seems to work. Any suggestions on h ...

Pagination with Thymeleaf in Spring Boot

I'm facing a challenge with pagination and need help resolving it. Whenever I try to access the index page, I receive the following error message: There was an unexpected error (type=Internal Server Error, status=500). Exception evaluating Spring ...

Creating a dynamic page footer for a PDF document using Rotativa's content generation capabilities

As I work on generating a PDF, my employer has requested that I add a footer to each page of the document. Currently, the PDF is being created using Rotativa, where an HTML page is converted into a PDF. However, I am facing a challenge in determining the ...

Challenges with the dropdown menu navigation bar

I am struggling with my dropdown menu and sign up/sign in buttons as they are not aligning properly. I have tried various coding methods but haven't been able to fix the issue. Can someone provide me with suggestions on how to rectify this problem? c ...

lost websession while window.location.replace or href

I encountered an issue with losing the web session when trying to redirect from webform1 to webform2 using various methods, such as window.location.replace("webform2.aspx") and passing "/webform2.aspx" as a parameter. Despite my efforts, the session is los ...

Leverage the power of Bootstrap 4 without incorporating its pre-built components

Is it possible to utilize Bootstrap 4 without its components? The diagram below seems to suggest otherwise, correct? My Scenarios: I need to implement Angular Material components instead of Bootstrap components. It's acceptable to use Bootstrap 4 ...

What is the best way to establish a maximum limit for a counter within an onclick event?

I'm struggling to figure out how to set a maximum limit for a counter in my onclick event. Can someone help me? What is the best way to add a max limit to the counter of an onclick event? Do I need to use an if statement? If yes, how should it be w ...

Manipulate container (div) to reveal and conceal

My jQuery was working fine until I added some more divs to my HTML. I'm now trying to toggle the opening and closing of a discussion container named discussionContainer with a click on the button replyButton. Any assistance would be highly appreciated ...

Exploring the dimensions of elements in Polymer using offsetHeight and offsetWidth

Looking for advice on running a script when the page loads that relies on the offsetHeight and offsetWidth properties of an element. I've tried calling the script within the "ready" and "attached" functions, but it doesn't seem to be running when ...

Tips for successfully using `cols=""` within a grid container alongside a textarea

It seems that both Chrome and Firefox are not following the cols attribute on textarea elements within a grid container: .grid { display: grid; } textarea:not([cols]) { width: 100%; } <h2>Not in a grid container:</h2> <div> <tex ...

The expected outcome of the value display in CSS is not being achieved as anticipated

Here is some HTML code: <!DOCTYPE html> <html> <head> <title>Testing Page</title> <link rel="stylesheet" type="text/css" href="style.css"> </head> <body> <h1 class="hid ...

Is there a way to automatically scroll 50 pixels down the page after pressing a button?

Is there a way to make my page scroll down in Angular when a button is clicked? I attempted to use this code, but it didn't have the desired effect. What is the best method for scrolling the page down by 50px? window.scrollBy(0, 50); ...

Tips for inserting HTML code within session statements

When a user signs in, I want to display this content. However, when I try to include the code within the echo statement, it doesn't work. How can I achieve this? <?php if(isset($_SESSION['userID'])){ echo 'PLACE CODE HERE'; } ? ...

Is it possible to rearrange div elements within different containers using media queries and CSS in Bootstrap4?

I've been utilizing the first/last utility in BS4, but my scenario requires relocating an element to and from a completely different section of the page. For instance, let's imagine I have the following setup: <div id='area1'> ...

What is the best way to create a CSS grid with horizontal overflow?

I'm currently working on a 4-column layout using CSS grid. As the browser width reaches a specific breakpoint, I want the first column to be fixed on the left side of the browser (X-axis) while the other columns scroll under it. Right now, I am utiliz ...

I encountered an issue while attempting to retrieve data using route parameters. It seems that I am unable to access the 'imagepath' property as it is undefined

Is there a way to access data when the page loads, even if it is initially undefined? I keep getting this error message: "ERROR TypeError: Cannot read properties of undefined (reading 'imagepath')". How can I resolve this issue? import { Compone ...

How can I make the HTML links in my Django email clickable?

I recently used Django to send the email shown below: subject, from_email, to = 'site Registration', '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="30434540405f424470435944551e535f5d5">[email protec ...

Navigating through AngularJS routes leads to an unexpected directory being added

Assigned to an AngularJS project after the departure of a team member, I found myself navigating unfamiliar territory as a Python/Java developer. Despite its outdated AngularJS version 1.0.8, I aim to modernize the system once it's stable. An issue h ...

Combining DataTables with multiple tables sourced from various JSON arrays

I am trying to display data from two different arrays within the same JSON source in two separate tables, but my code seems to be malfunctioning. JSON Information: { "Policies": [ { "name": "A", "id": "1", "score": "0" } ], ...