Search code examples
javascriptcssreactjstypescriptstyled-components

Nesting styled-components 'Atoms' together in 'Molecules' -> Styling / Positioning


I need to create a React Component Library

For this i use React with Typescript and styled-components.

I got stuck when i try to reuse my Atoms in a Molecule...

I create my Button Atom Component like this:

interface IButtonProps {
    text?: string
    onClick?: React.MouseEventHandler<HTMLButtonElement>
}

const StyledButton = styled.button<IButtonProps>`
  height: 70px;
  width: 70px;
  border: none;
  border-radius: 5px;
  background-color: #88BDBC;
  color: #254E58;
  font-family: Alata, sans-serif;
  font-size: 35px;
  transition: all 350ms;

  &:hover {
    background-color: #254E58;
    color: #88BDBC;
  }

  &:active {
    background-color: #112D32;
    color: #88BDBC;
  }
`;

const Button = ({
   text = "",
   onClick
}: IButtonProps): React.ReactElement => {
    return (
        <StyledButton onClick={onClick}>{text}</StyledButton>
    );
};

This is only a really not perfect Example for my Atoms. I create all Atoms like this. I only define the Style inside the Atoms -> Colors, Borders, Margins and so on. Not the Styles outside -> For Example Padding then i think its depends much in which context this Button is used.

So I'm very encapsulated.

When i want to use the Button in the for example 'Controller' Molecule then i need to give that Button some Positions and maybe some Paddings etc.

But in my Parent Styled Component i doesn't now how to Point them correctly. Especially when i have some bigger mix of Components like here.

interface IControllerProps {
    text1: string;
    text2: string;
    text3: string;
    onClick?: React.MouseEventHandler<HTMLButtonElement>
}

const StyledController = styled.div<IControllerProps>`
  /* ... */
`;

const Controller = ({
    onClick
}: IControllerProps) => {
    const [powerOn, setPowerOn] = React.useState(false);
    const [bankType, setBankType] = React.useState(false);
    const [volume, setVolume] = React.useState(50);

    return (
        <StyledController>
            <Text text="Hello"/>
            <Switch checked={powerOn} onChange={(e: React.ChangeEvent<HTMLInputElement>) => {setPowerOn(e.target.checked)}}/>
            <Button onClick={() => false}/>
            <Text text="Hello"/>
            <RangeSlider value={volume} min={0} max={100} onChange={(e: React.ChangeEvent<HTMLInputElement>) => setVolume(parseInt(e.target.value))} />
            <Text text="Hello"/>
            <Switch checked={bankType} onChange={(e: React.ChangeEvent<HTMLInputElement>) => {setBankType(e.target.checked)}}/>
            <Button onClick={onClick}/>
            <Button onClick={onClick}/>
        </StyledController>
    )
};

Do i need to work with Propertys to give that to the Button ... Point everything with pseudoclasses ... Define everything in the Button (But what is with flexibility to Context of the reusable Button) ...

What is the best practice for that?


Solution

  • You target the styles like so (I answer in javascript for less complexity):

    // Button.react.js
    export const StyledButton = styled.button`
      background-color: #88bdbc;
    `;
    
    // Controller.react.js
    import { StyledButton } from './Button.react.js';
    
    const StyledController = styled.div`
      ${StyledButton} {
        background-color: blue;
      }
    `;
    

    Please check the related docs.