Utilizing @chakra-ui/theme-tools

The secret to building incredibly nice and clickable buttons fast with Chakra UI is to use the included theme-tools package. This package, while not featured in the Boilerplate's package.json is bundled with @chakra-ui/react, so importing should not be a problem (despite what your IDE says!).

Specifically, we want to import the darken function from @chakra-ui/theme-tools. This will allow us to quickly get darker shades of any colours we use on a button, so that we can create great hover and active states without having to manually work out colours, if a designer hasn't already supplied them.

Building using darken and lighten

Let's say we have our button that starts off looking like this:

import React from 'react'
import * as Chakra from '@chakra-ui/react'

export const Button = (props: Chakra.ButtonProps) => {
  
  return (
    <Chakra.Button
      px={{base: "10px", xl: "25px"}}
      backgroundColor="#f00"
      {...props}
    />
  )

}

It'll look fine, but you'll notice that if you hover over it, the hover and active states are variants of grey (i.e. not in line with our button color).

So let's add our hover state like this:

import React from 'react'
import * as Chakra from '@chakra-ui/react'
import {darken} from '@chakra-ui/theme-tools'

export const Button = (props: Chakra.ButtonProps) => {
  
  return (
    <Chakra.Button
      px={{base: "10px", xl: "25px"}}
      backgroundColor="#f00"
      _hover={{
        backgroundColor: darken("#f00", 10)
      }}
      {...props}
    />
  )

}

With this extra _hover prop and the darken function, we've just created a fantastic hover state that is in keeping with our original button colour. In the darken function, our first argument is our hex colour string, and our second argument is the amount we want to darken the colour. Now let's add our active state:

import React from 'react'
import * as Chakra from '@chakra-ui/react'
import {darken, lighten} from '@chakra-ui/theme-tools'


export const Button = (props: Chakra.ButtonProps) => {
  
  return (
    <Chakra.Button
      px={{base: "10px", xl: "25px"}}
      backgroundColor="#f00"
      _hover={{
        backgroundColor: darken("#f00", 10)
      }}
      _active={{
        backgroundColor: lighten("#f00", 5)
      }}
      {...props}
    />
  )

}

Now we've just added an active state as well. Fantastic!

It's common for hover and active states to be different, with the active state usually being lighter or the same colour as the original state. Play around with a few different choices to see what looks best for the individual project.

Adding a _focus state

It's import to also add focus pseudo states if the project requires it. Focus as a state will be shown whenever the use is using the tab key to move around the website, or some other assistive technology. Therefore, it's important that they know they current element they have selected!

Chakra UI handles our focus state for us automatically if we don't want to do it custom - it'll add a light slightly transparent blue box shadow to every tabbable element (i.e. buttons, inputs, links, etc) on focus. However, using the _focus prop allows us to customise this more, much like we do with _hover and _active.

Here's an example of that:

import React from 'react'
import * as Chakra from '@chakra-ui/react'
import {darken, lighten} from '@chakra-ui/theme-tools'


export const Button = (props: Chakra.ButtonProps) => {
  
  return (
    <Chakra.Button
      px={{base: "10px", xl: "25px"}}
      backgroundColor="#f00"
      _hover={{
        backgroundColor: darken("#f00", 10)
      }}
      _active={{
        backgroundColor: lighten("#f00", 5)
      }}
      _focus{{
        backgroundColor: lighten("#f00", 3)
      }}
      {...props}
    />
  )

}