DEV Community

Stephen Charles Weiss
Stephen Charles Weiss

Posted on • Originally published at stephencharlesweiss.comblog on

Global Themes, Variants, And Modes With Styled-Components

If I were to list my strengths, web design wouldn’t top the list. None the less, I like learning about it and know that I’ll continue to improve over time by chipping away.

One thing I’ve been struggling with since adding a dark mode to my site (I look forward to making this a much more pleasant experience soon), was how the mode was intended to interact with the global theme. And then what happens if you want variants for components?

I put together a CodeSandBox to play around with the concepts.

Because it’s such a simple single page, I can see how all of the pieces come together and interact. It’s also made clear why my coworker, Justin Connor, put together a library called styled-variants!

Dealing with variants can quickly become a hassle - particularly if you’re duplicating the logic between modes.

The full code is below.

import React from "react";
import "./styles.css";
import styled, { ThemeProvider } from "styled-components";

const theme = {
  light: {
    bg: "powderblue",
    fs: "72px",
    maxWidth: 1000
  },
  dark: {
    bg: "red",
    color: "white",
    fs: "72px",
    maxWidth: 1000
  }
};

const buttonVariant = {
  light: {
    primary: {
      boxShadowColor: "teal"
    },
    secondary: {
      boxShadowColor: "grey"
    }
  },
  dark: {
    primary: {
      boxShadowColor: "orange"
    },
    secondary: {
      boxShadowColor: "orange"
    }
  }
};

const Title = styled.h1`
  background-color: ${({ theme, mode }) => theme[mode].bg};
  font-size: ${props => props.theme[props.mode].fs};
  color: ${({ theme, mode }) => (mode === "dark" ? theme[mode].color : "")};
`;

const Button = styled.button`
  box-shadow: 0.25rem 0.25rem
    ${({ theme, mode, variant }) => theme[mode][variant].boxShadowColor};
`;

const Wrapper = styled.div`
  background-color: ${({ theme, mode }) => theme[mode].bg};
  padding: 1rem;
`;

function App() {
  const [mode, setMode] = React.useState("light");
  function handleClick() {
    const nextMode = mode === "light" ? "dark" : "light";
    return setMode(nextMode);
  }

  return (
    <ThemeProvider theme={theme}>
      <Wrapper className="App" mode={mode}>
        <Title mode={mode}>Hello CodeSandbox</Title>
        <h2>The current mode is: {mode}</h2>
        <Button
          mode={mode}
          variant={"primary"}
          theme={buttonVariant}
          onClick={handleClick}
        >
          Toggle Mode
        </Button>
      </Wrapper>
    </ThemeProvider>
  );
}

export default App;

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs