How to use styled-system with typescript
Tags: typescript, react, css, javascript
Published: 2021-01-09 19:11:00

> Originally published at [timrichter.dev](https://timrichter.dev/blog/how-to-use-typed-system-with-typescript)

Styled-Components ❤️. There are a bunch of libraries already written for it one of which is styled-system which simplifies the creation of a component-based design system.

Now styled-system is awesome but I had some trouble finding good ways of integrating it with typescript especially when using custom components. So here is a little guide on how to do it 😉

## Prerequisite

If you haven't already install the types for styled-system.

```bash
npm install -D @types/styled-system
# or with yarn
yarn add -D @types/styled-system
```

## Normally Styled Tags

```jsx
import { layout, LayoutProps } from 'styled-system';

const Image = styled.img<LayoutProps>`
  ${layout}
`;
```

Styled-Components doesn't know about us using the layout props in our Image Component so we have to declare it explicitly with "LayoutProps".

> There is a props equivalent for everything in Styled-System for example color is ColorProps, space is SpaceProps and so on.

## Custom Components

```jsx
import { layout, LayoutProps, position, PositionProps } from 'styled-system';

interface Props extends PositionProps, LayoutProps {
  children: React.ReactNode;
}

const Container = styled.div<Props>`
  ${position};
  ${layout};
`;

const DropdownMenu: React.FC<Props> = ({ children, ...props }) => {
  return <Container {...props}>{children}</Container>;
};
```

The important parts here are to pass the rest of the props to the element that should be styled (in this case 'Container') and merging layout, position and custom props (here 'children') into a single type and then passing that to the styled component and the component itself 😁

## Advanced Custom Components

```jsx
import { space, SpaceProps } from 'styled-system';

interface ContainerProps extends React.HTMLAttributes<HTMLDivElement> {
  isOwner: boolean;
}

type Props = ContainerProps & SpaceProps & {
    content: string;
};

const Container = styled.div<ContainerProps>`
  ${space};
  ${(props) =>
    props.isOwner ? 'align-self: flex-end' : 'align-self: flex-start'
   };
`;

const Message: React.FC<Props> = ({ content, isOwner, ...props }) => {
  return (
    <Container isOwner={isOwner} {...props}>
      {content}
    </Container>
  );
};
```

This looks daunting 😅 We're gonna go through it one by one.

```jsx
interface ContainerProps extends React.HTMLAttributes<HTMLDivElement> {
  isOwner: boolean;
}

const Container = styled.div<ContainerProps>`
  ${space};
  ${(props) =>
    props.isOwner ? 'align-self: flex-end' : 'align-self: flex-start'
   };
`;
```

We want to give the styled div a custom prop "isOwner" to style it conditionally. For this we have to extend the props that the div element expects (HtmlAttributes)

```jsx
type Props = ContainerProps & SpaceProps & {
    content: string;
};

const Message: React.FC<Props> = ({ content, isOwner, ...props }) => {
  return (
    <Container isOwner={isOwner} {...props}>
      {content}
    </Container>
  );
};
```

We combine all props from the container, space props and our custom "content"-prop together into one type and pass that to the component. 
In the end we can pass:

- All Props that a normal div element would except, these would get passed to our Container
- All Space Props from styled-system, these get also passed to our Container
- Our Custom Props "isOwner" and "content", "isOwner" get's passed to the Container and "content" will be the child

We have a strongly typed Component that leverages styled-system, styled-components and custom props 🥳