Swizec Teller - a geek with a hatswizec.com

Senior Mindset Book

Get promoted, earn a bigger salary, work for top companies

Senior Engineer Mindset cover
Learn more

    Variants – a quick tip for better React components

    Say you're building a component that shows up in lots of places, like a header.

    Look at designs and sure enough, same header on every page. Logo, few buttons, username. You create a reusable component. DRY all the way.

    const Header = () => {
      return (
        <Box>
          <Logo />
          <MenuItem />
          <MenuItem />
          <UserMessages />
          <UserProfile />
        </Box>
      )
    }
    

    Fantastic! You have a header that works everywhere.

    A new page appears

    "Hey, header looks weird on homepage. Where's the signup button?"

    Your designer's not happy. Header that's the same everywhere can't be same on the homepage. That's for marketing, they need signups.

    obviously 🙄

    You add a prop.

    const Header = (props: { showSignup: boolean }) => {
      return (
        <Box>
          <Logo />
          <MenuItem />
          <MenuItem />
          {!props.showSignup && <UserMessages />}
          {!props.showSignup && <UserProfile />}
          {props.showSignup && <SignupButton />}
        </Box>
      )
    }
    

    Cool, you've kept it DRY. Same header, same styling, signup yes or no.

    A funnel shows up

    "Hey, users are getting distracted out of this purchase funnel. Header too busy"

    Your universal header is costing you money. When users are on the path to paying, you want nothing to stand in their way.

    Another boolean!

    "Oh and let's pretend this is a fullscreen modal, add a close button. Keep the logo"

    Two booleans!

    aqV7k1png2f49bb
    const Header = (props: {
      showSignup: boolean
      hideMenu: boolean
      showClose: boolean
    }) => {
      return (
        <Box>
          <Logo />
          {!props.hideMenu && <MenuItem />}
          {!props.hideMenu && <MenuItem />}
          {!props.showSignup && <UserMessages />}
          {!props.showSignup && <UserProfile />}
          {props.showSignup && <SignupButton />}
          {props.showClose && <CloseButton />}
        </Box>
      )
    }
    

    Well that's not confusing at all. With 3 booleans, your header has 8 possible incantations.

    Possible incantations of Header component
    Possible incantations of Header component

    Add one more ask from design and you're up to 16.

    😅

    You've created a mess

    Your beautiful universal header component is hard to use. Complexity is exploding, the code is getting hairy, and you're the only person on your team who knows how to hold it.

    For everyone else it's frustrating as heck. Get it right for this screen, breaks on that screen.

    Debugging feels like whack-a-mole.

    And I'm showing you a simple example. In production code these booleans start interacting. If hideMenu and showSignup then do X, otherwise if not showClose do Y.

    Nobody wants to touch your component ever again. It's too tricky.

    Variants to the rescue

    How many of those 8 incantations are valid?

    I count 3.

    Identify your variants
    Identify your variants

    Then why allow the other 5? If 5 out of 8 ways to use your component are bugs, something's wrong.

    Here's what you do 👉 turn those flags into a variant prop. Use TypeScript and you even get autocomplete 😍

    const Header = (props: { variant: "homepage" | "funnel" }) => {
      let hideMenu, showClose, showSignup
    
      switch (variant) {
        case "homepage":
          showSignup = true
        case "funnel":
          hideMenu = true
          showClose = true
      }
    
      return (
        <Box>
          <Logo />
          {!hideMenu && <MenuItem />}
          {!hideMenu && <MenuItem />}
          {!showSignup && <UserMessages />}
          {!showSignup && <UserProfile />}
          {showSignup && <SignupButton />}
          {showClose && <CloseButton />}
        </Box>
      )
    }
    

    Now the rest of your team can use your header with ease: <Header variant="..." />. And thanks to TypeScript their IDE tells them what's available.

    AND we found a bug in my pseudocode. You don't want user menus showing up in funnel headers 😅

    Cheers,
    ~Swizec

    PS: quick tip for shorter emails 👉 break your wrist

    Published on March 2nd, 2021 in Technical, React, Lessons

    Did you enjoy this article?

    Continue reading about Variants – a quick tip for better React components

    Semantically similar articles hand-picked by GPT-4

    Senior Mindset Book

    Get promoted, earn a bigger salary, work for top companies

    Learn more

    Have a burning question that you think I can answer? Hit me up on twitter and I'll do my best.

    Who am I and who do I help? I'm Swizec Teller and I turn coders into engineers with "Raw and honest from the heart!" writing. No bullshit. Real insights into the career and skills of a modern software engineer.

    Want to become a true senior engineer? Take ownership, have autonomy, and be a force multiplier on your team. The Senior Engineer Mindset ebook can help 👉 swizec.com/senior-mindset. These are the shifts in mindset that unlocked my career.

    Curious about Serverless and the modern backend? Check out Serverless Handbook, for frontend engineers 👉 ServerlessHandbook.dev

    Want to Stop copy pasting D3 examples and create data visualizations of your own? Learn how to build scalable dataviz React components your whole team can understand with React for Data Visualization

    Want to get my best emails on JavaScript, React, Serverless, Fullstack Web, or Indie Hacking? Check out swizec.com/collections

    Did someone amazing share this letter with you? Wonderful! You can sign up for my weekly letters for software engineers on their path to greatness, here: swizec.com/blog

    Want to brush up on your modern JavaScript syntax? Check out my interactive cheatsheet: es6cheatsheet.com

    By the way, just in case no one has told you it yet today: I love and appreciate you for who you are ❤️

    Created by Swizec with ❤️