---
title: Component Style
description: How to create and theme custom components.
category: 'theming'
---

Writing component styles in a way that is easy to maintain over the life of a
growing and changing project is a challenging task.

To solve this, we came up with the idea of style configuration or `styleConfig`.
This is a consistent theming API that makes component styling easy to understand
and maintain.

## Base styles and Modifier styles

Most component style consists of **base or default styles** and **modifier
styles** that alter its size or visual style based on some properties or state.

Common modifier styles includes:

- **Size:** A component can have different sizes (e.g. small, medium, large)
- **Variant:** A component can have different visual styles (e.g. outline,
  solid, ghost)
- **Color scheme:** For a given variant, a component can have different color
  schemes (e.g. an outline button with a red color scheme)
- **Color mode:** A component can change its visual styles based on color mode
  (e.g. light or dark).

### Single part and multipart components

Most components we build today are either single part components (e.g. Button,
Badge) or multipart components (e.g. Tabs, Menu, Modal).

**A single part component** is a component that returns a single element. For
example, the `<Button>` component renders a `<button>` HTML element:

```jsx live=false
// This component renders only one element (<button>)
<Button>My button</Button>
```

**A multipart component** is a component that has multiple parts, and require
these parts to work correctly. This is commonly referred to as a composite
component.

For example, a `Tabs` component consists of `TabList`, `Tab`, `TabPanels`, and
`TabPanel`. Styling this component as a whole might require styling each
component part.

```jsx live=false
<Tabs>
  <TabList>
    <Tab>Tab 1</Tab>
    <Tab>Tab 2</Tab>
  </TabList>
  <TabPanels>
    <TabPanel>Tab 1</TabPanel>
    <TabPanel>Tab 2</TabPanel>
  </TabPanels>
</Tabs>
```

## Styling single part components

The basic API for styling a single part component is:

```jsx live=false
import { defineStyleConfig } from '@chakra-ui/react'

export default defineStyleConfig({
  // Styles for the base style
  baseStyle: {},
  // Styles for the size variations
  sizes: {},
  // Styles for the visual style variations
  variants: {},
  // The default `size` or `variant` values
  defaultProps: {},
})
```

> The `defineStyleConfig` function provide us with better type safety out of the
> box.

Let's say we want to create a custom button component following the design spec
below.

<Img mt='10' mb='12' src='/button-spec.png' />

Here's a contrived implementation of the design:

```tsx live=false
import { defineStyleConfig } from '@chakra-ui/react'

const Button = defineStyleConfig({
  // The styles all button have in common
  baseStyle: {
    fontWeight: 'bold',
    textTransform: 'uppercase',
    borderRadius: 'base', // <-- border radius is same for all variants and sizes
  },
  // Two sizes: sm and md
  sizes: {
    sm: {
      fontSize: 'sm',
      px: 4, // <-- px is short for paddingLeft and paddingRight
      py: 3, // <-- py is short for paddingTop and paddingBottom
    },
    md: {
      fontSize: 'md',
      px: 6, // <-- these values are tokens from the design system
      py: 4, // <-- these values are tokens from the design system
    },
  },
  // Two variants: outline and solid
  variants: {
    outline: {
      border: '2px solid',
      borderColor: 'purple.500',
      color: 'purple.500',
    },
    solid: {
      bg: 'purple.500',
      color: 'white',
    },
  },
  // The default size and variant values
  defaultProps: {
    size: 'md',
    variant: 'outline',
  },
})
```

Makes sense right? Now, let's update the theme to include this new component
style.

```jsx live=false
import { extendTheme } from '@chakra-ui/react'

const theme = extendTheme({
  components: {
    Button,
  },
})
```

**And that's it!** You can use your new Button along with its custom variants
throughout your app. But what if we want to create a custom component that's not
part of Chakra UI? Let's use the following design spec for a Card component:

<Img mt='10' mb='12' src='/card-spec.png' />

Here's a contrived implementation of the design:

```jsx live=false
const Card = defineStyleConfig({
  // The styles all Cards have in common
  baseStyle: {
    display: 'flex',
    flexDirection: 'column',
    background: 'white',
    alignItems: 'center',
    gap: 6,
  },
  // Two variants: rounded and smooth
  variants: {
    rounded: {
      padding: 8,
      borderRadius: 'xl',
      boxShadow: 'xl',
    },
    smooth: {
      padding: 6,
      borderRadius: 'base',
      boxShadow: 'md',
    },
  },
  // The default variant value
  defaultProps: {
    variant: 'smooth',
  },
})
```

As with the Button component, we'll update the theme to include the new Card
component style.

```jsx live=false
import { extendTheme } from '@chakra-ui/react'

const theme = extendTheme({
  components: {
    Card,
  },
})
```

But in this case we'd have to **consume** these styles because the `Card`
component is not a built-in component in Chakra UI.

### Consuming style config

Since the new Card component is **not** part of Chakra UI we need to create a
new React component and consume the style we just created. We can do that using
`useStyleConfig` hook.

### useStyleConfig API

```jsx live=false
const styles = useStyleConfig(themeKey, props)
```

#### Parameters

- `themeKey`: the key in `theme.components` that points to the desired
  styleConfig.
- `props`: the options object used to compute the component styles. It typically
  consists of the `size`, `variant`, and `colorScheme`

#### Return Value

The computed styles for the component based on `props` passed. If no `props` is
passed, the `defaultProps` defined in the style config will be used.

```jsx live=false
import { Box, useStyleConfig } from '@chakra-ui/react'

function Card(props) {
  const { variant, ...rest } = props

  const styles = useStyleConfig('Card', { variant })

  // Pass the computed styles into the `__css` prop
  return <Box __css={styles} {...rest} />
}
```

> Please note that we are passing the styles to the prop `__css`. It has the
> same API as [the `sx` prop](/docs/styled-system/the-sx-prop), but has a lower
> style priority. This means you can override the style properties with chakra
> style props.

And lastly - the fun part - let's use our custom Card component anywhere in our
app:

```jsx live=false
// 1. Using the default props defined in style config
function Usage() {
  return (
    <Card>
      <Image
        src='https://chakra-ui.com/eric.jpg'
        rounded='full'
        w={32}
        h={32}
        boxShadow='md'
      />
      <Heading mt={6} maxW={60} size='lg' textAlign='center' color='gray.700'>
        Welcome back, Eric
      </Heading>
      <Text mt={6} mb={6} size='sm' color='blackAlpha.500'>
        Use your fingerprint to continue.
      </Text>
      <Image src='/fingerprint.png' w={32} h={32} />
    </Card>
  )
}

// 2. Overriding the default
function Usage() {
  return (
    <Card variant='smooth'>
      <Image
        src='https://chakra-ui.com/eric.jpg'
        rounded='full'
        w={32}
        h={32}
        boxShadow='md'
      />
      <Heading mt={6} maxW={60} size='lg' textAlign='center' color='gray.700'>
        Welcome back, Eric
      </Heading>
      <Text mt={6} mb={6} size='sm' color='blackAlpha.500'>
        Use your fingerprint to continue.
      </Text>
      <Image src='/fingerprint.png' w={32} h={32} />
    </Card>
  )
}
```

## Styling multipart components

This is very similar to styling single part components with a few differences
you need to be aware of.

- Given that multipart refers to a component with multiple parts, you'll need to
  define the parts, and pass them into the `createMultiStyleConfigHelpers`
  function
- You'll need to provide styles for each `part`, `baseStyle`, `sizes`, and
  `variants`.

> **Pro tip 💡**: If you're looking for a list of parts of a multipart component
> you can check it by clicking on the **"View theme source"** button at the top
> of the documentation page for that certain component. Check out
> [this](https://chakra-ui.com/docs/components/overlay/modal) example.

Here's what the style config for multipart components looks like:

```jsx live=false
export default {
  // The parts of the component
  parts: [],
  // The base styles for each part
  baseStyle: {},
  // The size styles for each part
  sizes: {},
  // The variant styles for each part
  variants: {},
  // The default `size` or `variant` values
  defaultProps: {},
}
```

For example, here's what the style configurations for a custom menu component
looks like:

```tsx live=false
import { createMultiStyleConfigHelpers } from '@chakra-ui/styled-system'

// This function creates a set of function that helps us create multipart component styles.
const helpers = createMultiStyleConfigHelpers(['menu', 'item'])

const Menu = helpers.defineMultiStyleConfig({
  baseStyle: {
    menu: {
      boxShadow: 'lg',
      rounded: 'lg',
      flexDirection: 'column',
      py: '2',
    },
    item: {
      fontWeight: 'medium',
      lineHeight: 'normal',
      color: 'gray.600',
    },
  },
  sizes: {
    sm: {
      item: {
        fontSize: '0.75rem',
        px: 2,
        py: 1,
      },
    },
    md: {
      item: {
        fontSize: '0.875rem',
        px: 3,
        py: 2,
      },
    },
  },
  variants: {
    bold: {
      item: {
        fontWeight: 'bold',
      },
      menu: {
        boxShadow: 'xl',
      },
    },
    colorful: {
      item: {
        color: 'orange.600',
      },
      menu: {
        bg: 'orange.100',
      },
    },
  },
  defaultProps: {
    size: 'md',
  },
})
```

Next, we'll update the theme object to include this new component style.

```jsx live=false
import { extendTheme } from '@chakra-ui/react'

const theme = extendTheme({
  components: {
    Menu,
  },
})
```

### Consuming multipart style config

Now that the style config is hooked into the theme, we can consume within any
component using `useMultiStyleConfig` hook.

We can also mount the computed styles on a specialized context provider called
`StylesProvider`. These styles will now be available to other sub-components. To
read from the context, use the `useStyles` hook.

### useMultiStyleConfig API

```jsx live=false
const styles = useMultiStyleConfig(themeKey, props)
```

#### Parameters

- `themeKey`: the key in `theme.components` that points to the desired
  styleConfig.
- `props`: the options object used to compute the component styles. It typically
  consists of the `size`, `variant`, and `colorScheme`

#### Return Values

The computed styles for each component part based on `size`, or `variant`. If
none of these were passed, the `defaultProps` defined in the styleConfig will be
used.

```jsx live=false
// 1. Import the components and hook
import { createStylesContext, useMultiStyleConfig } from '@chakra-ui/react'

const [StylesProvider, useStyles] = createStylesContext('Menu')

function Menu(props) {
  const { size, variant, children, ...rest } = props

  // 2. Consume the `useMultiStyleConfig` hook
  const styles = useMultiStyleConfig('Menu', { size, variant })

  return (
    <Flex __css={styles.menu} {...rest}>
      {/* 3. Mount the computed styles on `StylesProvider` */}
      <StylesProvider value={styles}>{children}</StylesProvider>
    </Flex>
  )
}

function MenuItem(props) {
  // 4. Read computed `item` styles from styles provider
  const styles = useStyles()
  return <Box as='button' __css={styles.item} {...props} />
}
```

That's it! We can use our newly created multipart component in our application:

```jsx live=false
// 1. Using the default props defined in style config
function Usage() {
  return (
    <Menu>
      <MenuItem>Awesome</MenuItem>
      <MenuItem>Sauce</MenuItem>
    </Menu>
  )
}

// 2. Overriding the default
function Usage() {
  return (
    <Menu size='sm'>
      <MenuItem>Awesome</MenuItem>
      <MenuItem>Sauce</MenuItem>
    </Menu>
  )
}
```

## Responsive modifiers

Just like any style prop, the `variant` and `size` properties can also be
responsive. We can use the
[responsive syntax](/docs/styled-system/responsive-styles) to achieve this.

```jsx
<Button
  size={{ base: 'xs', md: 'lg' }}
  variant={{ base: 'solid', md: 'ghost' }}
>
  Submit
</Button>
```
