loading...

Global Themes, Variants, And Modes With Styled-Components

stephencweiss profile image Stephen Charles Weiss Originally published at stephencharlesweiss.comblog on ・2 min read

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;

Discussion

pic
Editor guide