DEV Community

Nitzan Hen
Nitzan Hen

Posted on

How are you using Styled Components?

Hello!
Have you ever used style-components in a React project before? And, more generally, what are your thoughts of it?

I'm asking because we want to implement styled-components support for Agrippa, the React CLI for component generation! In fact, it's the second issue opened on our GitHub repository!

However, I unfortunately have never personally used styled-components in a production project, and while I did propose an implementation on the GitHub issue, it would definitely be better to hear an experienced input.

From what I've seen, different teams have used this tool in many different ways over the years.
Therefore, I'd love to hear your own experience with it, and how you're using it!
Even if you've used it in a small project or casually, speak up! the more experiences, the better - we could all learn something new as a result.

If you prefer, you're also more than welcome to join the discussion on the mentioned GitHub issue at Add support for styled components, and join the Agrippa community!

Thank you for your time!

(Cover image is from styled-components' docs, at https://styled-components.com/meta.png)

Discussion (24)

Collapse
larsejaas profile image
Lars Ejaas

Yeah, I have worked quite a bit with styled components actually. It is hands down my prefered way of styling things in React projects.
It can be a bit difficult to set up with TypeScript and the syntax for variables is a bit verbose - but it works extremely well!

Collapse
larsejaas profile image
Lars Ejaas

I prefer to write the styling in a seperate file and import the components where I need them. I normally use a global style file for some basic styles and then use *.style.ts files for anything else. Futhermore I will set up varous themes in seperate files.
I also tend to seperate stuff like breakpoints, margins, etc. that I use across themes into seperate files. I then import them where needed:

import {
  breakPoints,
  margins,
} from "styles/...";
Enter fullscreen mode Exit fullscreen mode

Regarding variables I tend to use destructuring when refering to props in styling:

background-color: ${({ theme }) => theme.color.backgroundSecondary};
Enter fullscreen mode Exit fullscreen mode

You can also refer to props on the component like this:

type CloseButtonProps = {
  modalType: TmodalType;
};

export const Closebutton = styled.button<CloseByttonProps>`
  position: absolute;
  right: ${(props) => (props.modalType === "search" ? "10px" : "16px")};
  ...
Enter fullscreen mode Exit fullscreen mode
Collapse
marcelxsilva profile image
Marcelo Silva

here you can use, an helper to destructuring props styling.

I use, an helper called getTheme with get from lodash.

export const getTheme = (themeProp: string) => ({ theme }: any): string => get(theme, themeProp);
Enter fullscreen mode Exit fullscreen mode

and can access this value getTheme('backgroundSecondary')

const backgroundSecondary = getTheme('backgroundSecondary')

background-color: ${backgroundSecondary}
Enter fullscreen mode Exit fullscreen mode

In index.js or index.ts of project you can use ThemeProvider from styled-components:

const theme = {
  ...colors,
  ...spacings,
  ...radius,
  ...breakpoints,
};

<ThemeProvider theme={theme}>
...
</ThemeProvider>
Enter fullscreen mode Exit fullscreen mode
Thread Thread
larsejaas profile image
Lars Ejaas

Hmm, I really love this. However, I tried it and couldn't make it work. Do you need a workaround when using several different themes? I am unsure how this would work?

Thread Thread
marcelxsilva profile image
Marcelo Silva

it is necessary to have the ThemeProvider configured at the root of the project. I usually use the routes file as children of the ThemeProvider.

when dealing with different themes, it will depend a lot on how you will inject the settings

Thread Thread
larsejaas profile image
Lars Ejaas

Yeah, that makes sense! But I need to do some rework on the way I implement themes in styled components. Would like to optimize my workflow further, and your idea using lodash is really great, I defininitely need to include this!

Collapse
nitzanhen profile image
Nitzan Hen Author

Thanks!! This is really helpful info, and seems like a good pattern.

Just to make sure I understand correctly, a typical component X's styles would be defined in X.style.ts/X.styles.js? And styles in that file would typically be declared using the tag-specific variants (e.g. styled.div, styled.h1)?

Also, based on your experience, is declaring styled-components styles inside the component file (X.tsx) itself a standard practice? Or do most developers use separate files for them (like you do)?

Lastly, do you perhaps have an example repo (yours or anyone else's) following this pattern? I'd love to have one as a point of reference.

Thanks again!

Thread Thread
larsejaas profile image
Lars Ejaas

Hi Nitzan

I only have an older repo to share, and honestly I would probably refactor the code a bit today, but feel free to take a look at it at: github.com/LarsEjaas/bruce-willis-app

It's a small page/web app - it's live here at bruce-willis.rocks/en

I am unsure that there is a best practice regarding separating code into separate files or not, but I like to do it this way. We use the same approach in the team where I work.

Let's say I am doing an "awesome button"

Then I would create a folder named AwesomeButton in the components folder.

This would contain:

AwesomeButton.tsx for the functional component,
AwesomeButton.styles.ts for the styles,
AwesomeButton.test.tsx for the tests and maybe
Awesome.stories.tsx if you use storybook.

Furthermore I would make an index.ts file where I would export the functional component like this:

export {default} from AwesomeButton.tsx
Enter fullscreen mode Exit fullscreen mode

This way I can import my AwesomeButton component like this inside my project:

import AwesomeButton from 'components/AwesomeButton'
Enter fullscreen mode Exit fullscreen mode

I think this pattern works well for large projects.

Thread Thread
larsejaas profile image
Lars Ejaas

Ahh, missed the part regarding tag-specific variants:

I use both of these:

export const StyledHeadline = styled.h1`
 //...styles
`
Enter fullscreen mode Exit fullscreen mode

and

import UnstyledComponent from 'components/...'

export const StyledComponent = styled(UnstyledComponent)`
  //...styles
`
Enter fullscreen mode Exit fullscreen mode
Thread Thread
nitzanhen profile image
Nitzan Hen Author

Thanks a lot for your detailed response!!!
This will be of great help to me.

Thread Thread
larsejaas profile image
Lars Ejaas

Ahh, you are welcome! Feel free to drop me a message if something is difficult with Styled Components. It can be a bit difficult at first...

Collapse
nitzanhen profile image
Nitzan Hen Author

My implementation, in a simple example, goes something like this:

import React from 'react';
import styled from 'styled-components'; // 1. Import styled-components

const AComponentStyled = styled(AComponent)`` // 2. Create styled variant

function AComponent({ className }) { // 3. Receive className prop

  //...

  return (
    // 4. Pass className prop to JSX root
    <div className={className} /> 
  )
} 

export default AComponentStyled; // 5. Export styled variant
Enter fullscreen mode Exit fullscreen mode

Of course, the CLI generalizes this example to any component, and supports Typescript, using a named export (instead of the default export), etc.

Most examples out there used the component-specific variants, such as styled.h1, but to me it felt that the more generic styled(component) are more useful - however if you are using the component-specific variants, do tell!

Collapse
bcheidemann profile image
Ben Heidemann

I use component specific variants quite regularly. Generally, as long as it's a simple component consisting of a single styled element (e.g. a div) I will use the component specific variants as I find them easier to read. However, I work a lot with Material UI and when styling MUI components I use styled(MuiComponent). Do you use the styled(Component) syntax you describe above for consistency or is there another reason?

Collapse
nitzanhen profile image
Nitzan Hen Author

This makes a lot sense!

I actually have used Material UI a lot as well, and I think I originally tended towards the generic styled(Component) syntax simply because I was used to MUI's way of doing things - where the definition of the styles for a component is closely tied to the component itself (at least that's how it was when MUI still used JSS).

However, I'm realizing more and more how useful and neat the tag-specific variants are! Cheers!

Collapse
jkierem profile image
Juan Miguel Gomez

Mostly for small reusable components. I try to keep it simple with styled components and not abuse them. I moved away from them for css heavy projects. Also theming is really easy so that is something I always use. I normally don't use all the features like style extension. I try to stay on the basic parts of the lib as the advanced features add a bit of complexity that make them harder to use in large code bases

Collapse
nitzanhen profile image
Nitzan Hen Author

Good to know! I'll try to keep the implementation simple.

If I may ask, what do you use for CSS heavy projects?

Collapse
jkierem profile image
Juan Miguel Gomez

Css modules with Sass or just Sass with a style loader so that I can import it in js.

Collapse
ksengine profile image
Kavindu Santhusa

Both styled-components and emotion.js are using stylis.js to parse styles. So personally I prefer goober.js which is less than 1kb

But please check the benchmarks before you change your library.

Tip: use bundlephobia.com to inspect the size of styled-components

Collapse
justiceotuya profile image
Justice Otuya

so how i use styled components is that the main container in the component is a styled component and everything inside the components are normal classes,

example

COMPONENT.TSX
const Container = ({...props}) => {

return (<StyledContainer props={currentColor,...propsIWantToUseInTheCSS}>
              <div className="box__red_or_blue">
             ......
              </div>
          </StyledContainer>)
}
Enter fullscreen mode Exit fullscreen mode
COMPONENT.STYLE.TS
export const StyledContainer = styled.div({currentColor:string}) => {
//style here are for styling the component itself, then you can add classes which are elements inside the styled component

padding:30px;
margin:20px
....

//element with a className inside the styled component, the styled component takes a  color props and passes it to the className

.box__red_or_blue {
color: ${props} => props.currentColor === "red" ? "red" : "blue"}
}

}
Enter fullscreen mode Exit fullscreen mode

since styled-components generate classes for each component, it will be hard to get clashes as the elements with classes and encapsulated and embedded with the styled component

Collapse
jt3k profile image
Andrey Gurtovoy

I use styled components gritting my teeth and getting nervous every time when I have to come into contact with it. I recommend that you do tooling, because right now it works very sadly in vscode sublime-text and and elsewhere. problems in the absence emmet, error-free work stylelint , and other nightmares. get busy with tools at last!

Collapse
rexgalilae profile image
RexGalilae

CSS modules is the cleanest approach for me.

Styled components respect no separation of concerns and are verbose

Collapse
nitzanhen profile image
Nitzan Hen Author

I'm actually a big fan of CSS modules too!
However, as far as I can tell there are many developers who use styled-components, so I'd like to have support for it in Agrippa (it already has CSS modules by default, btw).

Collapse
nipunadodan profile image
Nipuna Dodantenna • Edited on

Styled components are cool until it starts to affect other components

Collapse
larsejaas profile image
Lars Ejaas

@nipuna what issues have you come across? I haven't really experienced anything like that?