What I've learned using Chakra-Ui so far
Tags: react, webdev, css, beginners
Published: 2021-04-18 15:36:34

When I finished playing around with building a Design System(or part of it) for a project, before start coding one important question popped up: Which library should I use to style my components?

Lately, I've been working with styled-components but I wanted to try the trending ones right now: Tailwind CSS or Chakra-Ui.

After watching some videos and seeing how both looked like in code, I decided to go with Chakra-Ui.

So, in this article I'm going to share what my experience have been so far with Chakra-Ui after working with it during these last 2 days. Hopefully it can help people having their first steps with the library.


## 1. Creating a custom theme is a breeze

By default, Chakra-Ui already comes with a theme but we can customize it to best fit our design. And that was where I started to play with Chakra since I had created a design system.

The theme object is where we define the application's color pallete, type scale, font stacks, border radius values and etc. All Chakra components inherit from this default theme.

From the default theme, we can extend and overide tokens and also add new values to the theme. Customizing the it is as easy as:

1) Extending it with `extendTheme`:

```javascript

import { extendTheme } from '@chakra-ui/react'

const customTheme = extendTheme({
    colors: {
        lightGray: {
            default: '#C4C4C4',
            hover: '#EEEEEE',
            disabled: '#9E9E9E'
        }
    },
    // I'm just adding one more fontSize than the default ones
    fontSizes: {
        xxs: '0.625rem'
    },
    // I'm creating a new space tokens since the default is represented with numbers
    space: {
        xs: '0.25rem',
        sm: '0.5rem',
        md: '1rem',
        lg: '1.5rem',
        xl: '2rem',
        xxl: '3rem',
    }
})

export default customTheme
```

2) Passing to the `ChakraProvider`:

```javascript
import customTheme from './theme'

<ChakraProvider theme={customTheme}>
  <App />
</ChakraProvider>
```

3) Using it:

```javascript
import customTheme from './theme'

const BoxWithText= ({ text }) => (
  <Box padding='xs' borderRadius='lg'>
    <Text>{text}</Text>
  </Box>
)
```


## 2. Creating variants of components makes it easier to implement a design system

Besides customizing theme tokens we can also customize component styles.

Chakra component styles have a specific API that a component style consists of:
- `baseStyle`, the default style of a component
- `sizes`, represents styles for different sizes of a component
- `variants`, represents styles for different visual variants
- `defaultProps`, optional, to define the default `size` or `variant`.

From the docs, what the component style looks like:

```javascript
const ComponentStyle = {
  // style object for base or default style
  baseStyle: {},
  // styles for different sizes ("sm", "md", "lg")
  sizes: {},
  // styles for different visual variants ("outline", "solid")
  variants: {},
  // default values for `size` and `variant`
  defaultProps: {
    size: "",
    variant: "",
  },
}
```

With the possibility of customizing each component we can create variants for them to match pre-defined styles of a component. For example, in a design system you may have different variations of the typography to show different font sizes, font weights, etc. The same goes with components such as buttons, inputs, etc.

With variants we can create pre-defined styles for those components:

```javascript
import { extendTheme } from '@chakra-ui/react'

const customTheme = extendTheme({
    components: {
        Heading: {
            variants: {
                h1: {
                    fontSize: '4xl', fontWeight: 'bold'
                },
                h2: {
                    fontSize: '3xl', fontWeight: 'bold'
                }
            }
        },
        Text: {
            variants: {
                subtitle: {
                    fontSize: 'xl', fontWeight: 'medium'
                },
                body: {
                    fontSize: 'md', fontWeight: 'medium'
                }
              }
            }
        }
})

export default customTheme
```

And use it in our code:

```javascript

const Badge = ({ text }) => (
  <Box padding='xs' borderRadius='lg' w='max-content'>
    <Text variant='bodyExtraSmall'>{text}</Text>
  </Box>
)

```


## 3. Integrating with Storybook is not so smooth currently

One pain point I had with this begining of my journey with Chakra-Ui was trying to use Storybook to show my created components. For my workflow, I always create the components and their corresponding stories to be easier to see the different styles and create a component library.

However, when I created the stories with my Chakra components and checked the Storybook it did not load any styling I made with Chakra. I was frustrated at first but thanks to an [issue raised](https://github.com/chakra-ui/chakra-ui/issues/2527) I could get it working.

To fix that you can:

1) Modify the `main.js` file inside the `.storybook` folder to match the `webpackFinal` config that Chakra uses:

```javascript
const path = require("path");
const toPath = (_path) => path.join(process.cwd(), _path);

module.exports = {
  stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
  addons: [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/preset-create-react-app",
  ],
  webpackFinal: async (config) => {
    return {
      ...config,
      resolve: {
        ...config.resolve,
        alias: {
          ...config.resolve.alias,
          "@emotion/core": toPath("node_modules/@emotion/react"),
          "emotion-theming": toPath("node_modules/@emotion/react"),
        },
      },
    };
  },
};
```

2) Wrap the story decorator with the `ChakraProvider` in the `preview.js` file:

```javascript
import React from "react"
import { ChakraProvider } from '@chakra-ui/react'
import theme from '../src/theme'

export const parameters = {
  actions: { argTypesRegex: "^on[A-Z].*" },
}

const withChakra = (StoryFn) => {

  return (
    <ChakraProvider theme={theme}>
      <StoryFn />
    </ChakraProvider>
  )
}

export const decorators = [withChakra]
```

This is a temporary workaround that I believe can be resolved any time soon since they are already working on [it](https://github.com/chakra-ui/chakra-ui/issues/2694) :)


## 4. We can't create variants for Box but we can use Layer Styles or Text Styles 

Another "problem" I had was when I tried to create variants for the `Box` component. I wanted to create different types of `Badges` that I could simply choose the `variant` when inserting them on my components. My Badge consisted of a `Box` with a `Text` inside, the code I've shown in the previous snippets.

However, after finding this [issue](https://github.com/chakra-ui/chakra-ui/issues/2456) I understood that by design `Box` cannot receive variants in theme since it is a generic component, it represents a `div`.

To work around that, you could use the [`useStyleConfig`](https://next.chakra-ui.com/docs/theming/component-style#usestyleconfig-api) or use the `textStyle` or `layerStyle` props, docs [here](https://chakra-ui.com/docs/features/text-and-layer-styles).

Both props are used to avoid repeating specific text and layer properties and help us keep our components organized and consistent. They allow us to save styling attributes to re-use in other components, passing the corresponding prop to the component.

Since I only needed to change the background color and the border depending on the type of `Badge` I wanted, I used the layer style.

To solve this:
1) Extend the theme with new `layerStyles`:

```javascript
const customTheme = extendTheme({
    layerStyles: {
      defaultBadge: { bg:'lightGray.default' },
      outlinedBadge: { bg:'transparent', border: '1px solid #000000' },
      whiteBadge: { bg:'#FFFFFF' }
    }
})
```

2) Consume it in the component:

```javascript
const Badge = ({ text }) => (
  <Box layerStyle=`outlinedBadge` padding='xs' borderRadius='lg' w='max-content'>
    <Text variant='bodyExtraSmall'>{text}</Text>
  </Box>
)
```


# Conclusion

That's it for now. I hope you could get some tips when also starting your journey with Chakra-Ui. If I find more interesting points and learnings to share I may create another article as well :)

If it was somehow useful, leave it a :heart: or if you have more to add drop a comment.
Also, I'd love if we connect on [Twitter](https://twitter.com/c_rafael22) as well :)