Creating alternate versions using styled components

What is the most effective method for creating different styles using styled components? This is my current approach:

  const ButtonStyle = styled.button`
  padding:8px 20px;
  border:none;
  outline:none;
  font-weight:${props => props.theme.font.headerFontWeight};
  font-size:${props => props.theme.font.headerFontSize};
  display:block;
  &:hover{
    cursor:pointer;
  }
  ${({ variant }) =>
    variant == 'header' && css`
    background-color:${props => props.theme.colors.lightblue};
    color:${({ theme }) => theme.colors.white};
    &:active{
      background-color:${props => props.theme.colors.blue}
    }
    `
  }
  ${({ variant }) =>
    variant == 'white' && css`
    background-color:white;
    color:${({ theme }) => theme.colors.lightblue};
    &:active{
      color:${props => props.theme.colors.blue}
    }
    `
  }
`;

I'm unsure if this is the standard practice. I also adapt existing components to create new ones with slight adjustments

For example:

  const InnerDiv = styled(otherComponent)`
  position: unset;
  background-color: red;
  overflow-x: hidden;
  display: flex;
`;

Which approach is more preferable? Are there any superior alternatives?

Answer №1

Building on the ideas of others, here is my unique approach:

import styled, { css, DefaultTheme } from 'styled-components';

const variantStyles = (theme: DefaultTheme, variant = 'primary') =>
  ({
    primary: css`
      color: ${theme.colors.light};
      background: ${theme.colors.primary};
      border: 1px solid ${theme.colors.primary};
    `,
  }[variant]);

const Button = styled.button<{ variant: string }>`
  padding: 1rem;
  font-size: 0.875rem;
  transition: all 0.3s;
  cursor: pointer;

  ${({ theme, variant }) => variantStyles(theme, variant)}

  &:active {
    transform: translateY(1.5px);
  }
`;

export default Button;

Currently, only the primary variant is included as the default option, but you can easily add more variants by extending the variantStyles object.

To use different variants, simply pass the variant name as a prop or omit it to stick with the default one.

import { Button } from './HeroSection.styles';

<Button variant="primary">Start Learning</Button>

Answer №2

Here's my take on it:

In my opinion, the approach you took is probably the best way to handle it.

One alternative method I considered was creating an options object to map out the different variant possibilities, like so:

const variantOptions = {
  header: {
    backgroundColor: theme.colors.lightblue,
    color: theme.colors.white,
    active: theme.colors.blue,
  },
  white: {
    backgroundColor: "white",
    color: theme.colors.lightblue,
    active: theme.colors.blue,
  },
};

You could then incorporate this object into your styled component as follows:

const ButtonStyle = styled.button`
  padding: 8px 20px;
  border: none;
  outline: none;
  font-weight: ${(props) => props.theme.font.headerFontWeight};
  font-size: ${(props) => props.theme.font.headerFontSize};
  display: block;
  &:hover {
    cursor: pointer;
  }

  ${({ variant }) =>
    variant &&
    variantOptions[variant] &&
    css`
       background-color: ${variantOptions[variant].backgroundColor};
       color: ${variantOptions[variant].color};
       &:active {
          color: ${variantOptions[variant].active};
       }
   `}
`;

This setup allows for multiple button variants to be easily implemented:

<ButtonStyle variant="*wrong*">Button</ButtonStyle>
<ButtonStyle variant="header">Button</ButtonStyle>
<ButtonStyle variant="white">Button</ButtonStyle>
<ButtonStyle>Button</ButtonStyle>

Answer №3

When it comes to organizing Styled Component variants, I have a few techniques that help keep things structured and easy to scale.

If the variants are stored in the same file, I make use of inheritance properties like this:

const DefaultCard = styled.div`
    background-color: ${(props) => props.theme.primary};
`;

const CardHighlighted = styled(DefaultCard)`
    background-color: yellow;
`;

const CardDisabled = styled(DefaultCard)`
    background-color: ${(props) => props.theme.grey};
`;

For reusable components, I prefer using this method:

import styled from 'styled-components';

// Make sure to have a default class
const StyledBox = ({ className = 'standard', children }) => {
    return <Container className={className}>{children}</Container>;
};

/*
 * Default Box styles
 */
const Container = styled.div`
    padding: 10px;
`;

/*
 * Custom Box Variant 1
 */
export const StyledBoxHighlight = styled(StyledBox)`
    && {
        background-color: pink;
    }
`;

/*
 * Custom Box Variant 2
 */
export const StyledBoxMuted = styled(StyledBox)`
    && {
        background-color: ${(props) => props.theme.colors.grey.light};
    }
`;

export default StyledBox;

Usage example:

import StyledBox, { StyledBoxMuted, StyledBoxHighlight } from 'components/StyledBox';

const Page = () => {
    return (
        <>
            <StyledBox>Default Box</StyledBox>
            <StyledBoxMuted>Muted Box</StyledBoxMuted>
            <StyledBoxHighlight>Highlighted Box</StyledBoxHighlight>
        </>
    )
};

To learn more about this approach, check out my blog posts on the topic here and there.

Answer №4

There are various methods you can use to accomplish this task. An easy approach is by utilizing the package known as Styled-components-modifiers, which comes with clear and user-friendly documentation.

https://www.npmjs.com/package/styled-components-modifiers

Here's a simple example of how to use it:

import { applyStyleModifiers } from 'styled-components-modifiers';

export const TEXT_MODIFIERS = {
  success: () => `
  color: #118D4E;
 `,
 warning: () => `
 color: #DBC72A;
 `,

 error: () => `
 color: #DB2A30;
 `,
};

export const Heading = styled.h2`
color: #28293d;
font-weight: 600;
${applyStyleModifiers(TEXT_MODIFIERS)};
`;

Within your Component - import the Heading component and utilize the modifier prop to select different variants.

 <Heading modifiers='success'>
    Hello Buddy!!
 </Heading>

Answer №5

Styled components are often paired with Styled system, which offers support for variants and other useful features to enhance the functionality of Styled components. In this example, the Button prop variant is automatically linked to the keys of the variants object:

const buttonVariant = ({ theme }) =>
  variant({
    variants: {
      header: {
        backgroundColor: theme.colors.lightblue,
        color: theme.colors.white,
        active: theme.colors.blue,
      },
      white: {
        backgroundColor: 'white',
        color: theme.colors.lightblue,
        active: theme.colors.blue,
      },
    },
  })

const Button = styled.button`
  ${(props) => buttonVariant(props)}
`

Explore Styled System Variants at:

Answer №6

Utilize the variant API for applying styles to a component based on a single prop. This approach can be quite useful for accommodating subtle stylistic differences in button or typography components.

Simply import the variant function and include variant style objects in your component definition. To define variants inline, you have the option to leverage Styled System's syntax to access values from your theme.

// Sample Button with variants
import styled from 'styled-components'
import { variant } from 'styled-system'

const Button = styled('button')(
  {
    appearance: 'none',
    fontFamily: 'inherit',
  },
  variant({
    variants: {
      primary: {
        color: 'white',
        bg: 'primary',
      },
      secondary: {
        color: 'white',
        bg: 'secondary',
      },
    }
  })
)

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

The expansion animation for the Nextjs/React accordion box did not work as expected when utilizing tailwindcss

I am currently working on creating an animation for a collapsible box (accordion). My goal is to have the child component initially hidden with display:none. When I hover over the parent component, the child should be revealed and the dimensions of the pa ...

What is the best way to achieve text elements overlapping each other in CSS?

Imagine having the following HTML: <div> hello <div>hello</div> </div> Wouldn't it be cool if those two texts overlapped perfectly in the center? It doesn't matter which one overlaps the other. Do you think it' ...

What are some best practices for enhancing the elegance of this JS code?

Within my React app that utilizes Material UI components, I created a code snippet to handle the sizing of contact form fields. These fields are dynamic elements that can be added or removed based on certain configurations. Although the code I implemented ...

Is there a way to efficiently create an ng-repeat for multiple divs?

I am looking to iterate through a collection of divs, as mentioned below. Each object in the list will have content-data and a link to an image. The code provided shows individual entries for each list item, but I would like to retrieve it from the angular ...

Tips for managing a row click in a basic table with Material UI

Does anyone know how to extract all the data from a clicked row in the DenseTable component of the UI Material? Your help would be greatly appreciated. Here is the source code for the component I am using: import * as React from 'react'; import ...

Tips for effectively managing Navbar color adjustment while scrolling in Angular?

I'm currently working on an Angular project and I am looking to incorporate a navbar with a transparent background that changes color when scrolled. I am utilizing bootstrap classes for this particular task. The HTML code for my Navbar heading is as ...

What is the process for removing multiple rows at once in Material-UI DataGrid?

Seeking guidance on how to remove rows from the DataGrid from Material-UI by using checkboxes in React. I have not been able to find a suitable tutorial for performing this action with DataGrid, although there is one available for MaterialTable, which is n ...

Challenging glitch in the JavaScript code

My jQuery code seems to be functioning properly in online text editors like Fiddle and StackOverflow snippets. However, when I try to implement the same code in Brackets or view it on GitHub, the navbar scroll down animation fails to work as expected. You ...

How can you change a particular inline style using the Firefox browser?

I am looking for a solution to override an inline style on a specific webpage within the Firefox browser without access to the source code. Previously, I would manually modify the page source using Firefox development tools. Specifically, I encounter a we ...

Finding the best way to transfer text between DIV elements?

I have a dilemma involving two DIV elements positioned absolutely on the sides of an HTML page, much like this EXAMPLE: <div class="left"> </div> <div class="right"> </div> These are styled using the following CSS: .left{ pos ...

Unable to resize tables in IE when using CSS Flex layout

Having a bit of trouble with the flex layout. I've put together a FIDDLE project where when resizing the output box, table cells will align one to one beneath each other. It seems to work fine in Chrome and Firefox but not in IE when using table eleme ...

There was a TypeError that was not caught in the promise, stating that the function window.showOpenFilePicker is not valid

Encountering TypeError with File System Web API While experimenting with the File System Web API, I keep receiving a TypeError stating Uncaught (in promise) TypeError: window.showOpenFilePicker is not a function. I am unsure of what is causing this issue. ...

npm encountered an error: EPERM - Unable to perform the operation 'RENAME' due to insufficient permissions

Every time I run npm install, I encounter the following error: npm ERR! code EPERM npm ERR! syscall rename npm ERR! path C:\Users\Vaneeza10698\Downloads\ServiceQualityFinal\react-reduction\node_modules\npm\node_modul ...

In the realm of typesetting, a punctuated line gracefully weaves its way between two

I am trying to create two sentences with a fixed width of 30%, but the first words in my div go to the next line. The class="left" words are not displaying properly, and then my second div "words" gets mixed with the first div. HTML <div class="bg"> ...

Require presenting only four lists - slideDown in jQuery

I am trying to display only 4 out of 8 lists initially, and upon clicking a "more" button, the rest of the list should be revealed. Can someone please assist me with this? Below is the jQuery code: $(document).ready(function() { $("#accordion").hide(); ...

I'm encountering an issue with my React 18 application using TypeScript: the module './App' cannot be found

Encountering an issue while attempting to update to react 18. I'm curious if this problem is related to my file types. I am using Typescript, so do both the app and index files need to have a .tsx extension? Both the app and index files are located ...

Encountering console errors during the testing of a React component that utilizes a Font Awesome

In my react project, I am using font-awesome icons along with jest and enzyme for testing. The icons are showing up properly in the project, but during unit testing, I am encountering the following errors: console.error node_modules/@fortawesome/react-fon ...

The <link> element in the HTML file referring to the stylesheet {% static 'css/style.css' %} is not functioning properly

I am having trouble aligning text to the center in VS Code when linking CSS to HTML. The 'center-aliend' property doesn't seem to work for me. Can someone point out what I might be doing wrong? I am trying to position the text 'Hello St ...

Modify the css with JQUERY when there are no rows inside the tbody section

Is it possible to change the css using jquery if there are no rows in the table body? I have attempted this but my current approach is not working. I tried adding an alert within the if statement, but the alert did not appear. My goal is to hide the table ...

Is the menu not appearing in the header section of the HTML/CSS?

Hey there, I'm a new student diving into the world of HTML/CSS. I've been working on creating a page layout, but for some reason my menu links are appearing under the header section instead of within it. I'm a bit confused and could really u ...