DEV Community

Cover image for What I've learned using Chakra-Ui so far
Rafael Leitão
Rafael Leitão

Posted on • Edited on

What I've learned using Chakra-Ui so far

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:


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
Enter fullscreen mode Exit fullscreen mode

2) Passing to the ChakraProvider:

import customTheme from './theme'

<ChakraProvider theme={customTheme}>
  <App />
</ChakraProvider>
Enter fullscreen mode Exit fullscreen mode

3) Using it:

import customTheme from './theme'

const BoxWithText= ({ text }) => (
  <Box padding='xs' borderRadius='lg'>
    <Text>{text}</Text>
  </Box>
)
Enter fullscreen mode Exit fullscreen mode

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:

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: "",
  },
}
Enter fullscreen mode Exit fullscreen mode

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:

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
Enter fullscreen mode Exit fullscreen mode

And use it in our code:


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

Enter fullscreen mode Exit fullscreen mode

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 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:

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"),
        },
      },
    };
  },
};
Enter fullscreen mode Exit fullscreen mode

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

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]
Enter fullscreen mode Exit fullscreen mode

This is a temporary workaround that I believe can be resolved any time soon since they are already working on it :)

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 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 or use the textStyle or layerStyle props, docs here.

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:

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

2) Consume it in the component:

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

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 ❤️ or if you have more to add drop a comment.
Also, I'd love if we connect on Twitter as well :)

Top comments (17)

Collapse
 
dominiksumer profile image
Dominik Sumer

nice post, thanks for writing this together Carlos! 🙏

Collapse
 
carlosrafael22 profile image
Rafael Leitão

Thanks! Great that you liked it, Dominik :)

Collapse
 
adparris profile image
Andrew Parris

Thanks for posting this! I've been using Chakra UI for awhile now and LOVE it. Thought I'd give Storybook a go and well, because you wrote this, you know the initial outcome! It wasn't pretty. I searched for 'storybook js chakra ui' and this post came up. You're a rock star, my friend! 😀

Collapse
 
techmely profile image
Techmley

Love this post, have a lot of experiences in this, thank you!

Collapse
 
carlosrafael22 profile image
Rafael Leitão

Thanks for the feedback, Harry! Glad that you loved it :)

Collapse
 
abd1rahmane profile image
Abderrahmane M

Thanks a lot .

Collapse
 
carlosrafael22 profile image
Rafael Leitão

Thanks for the comment, Abderrahmane! I'm glad that it helped you :)

Collapse
 
makneta profile image
Magda Rosłaniec

Thanks for the post. I'm bookmarking it for the time I'll try Chakra-UI.

Collapse
 
carlosrafael22 profile image
Rafael Leitão

Thanks, Magda! Hopefully it'll be helpful to you :)

Collapse
 
alveshelio profile image
Helio Alves

Oi Carlos muito obrigado pelo post :)

Carlos, I was wondering if you had to create multi-part components. I'm trying to get it working but I'm not sure of the approach.

Collapse
 
carlosrafael22 profile image
Rafael Leitão

Massa que você gostou, Hélio! 🙂

Unfortunatelly I haven't used it yet. I tried to look in the docs and tried to find some other resources but I couldn't quite understand its use so I can't help you right now :( If I ended up using it and getting the grip of it I will share with you :)

Collapse
 
alveshelio profile image
Helio Alves

Yeah, I think, the docs lack quite some information I've tried to get help from the Discord channel but without look either. I'll keep trying to find info and maybe I'll write a post just like yours which is really good :)

Obrigado, abraço

Thread Thread
 
carlosrafael22 profile image
Rafael Leitão

Great, Helio! It would be a massive help if you share it after you understand how it works. There are certainly other devs with the same struggle.
I'm looking forward to reading your post :) Valeuzão :D

Collapse
 
hassan7744 profile image
hassan7744

Tanks sir

Collapse
 
hassan7744 profile image
hassan7744

Tanks sir

Collapse
 
bingo1392 profile image
Jan Žitník

Thank you man - perfect post. Especially the part with Storybook. You saved me a lot of time.

Collapse
 
natansevero profile image
Natan Severo

Amazing post! Thanks for share it with us