Advanced Theming

Now that you understand how to use Chakra UI theming API. Let's take a step further and see if we can adapt a component to color mode.

When defining the styles for the sizes or variants, you can either pass a style object or a function that returns a style object.

Single Part Component#

For a single part component like button, badge, etc. The style configuration has the following signature:

type StyleInterpolation = StyleObject | ((options: StyleOptions) => StyleObject)
interface StyleOptions {
theme: Theme
colorMode: 'light' | 'dark'
colorScheme: string
}
interface StyleConfig {
baseStyle: StyleInterpolation
sizes: { [size: string]: StyleInterpolation }
variants: { [variant: string]: StyleInterpolation }
defaultProps?: {
variant: string
size: string
}
}

For example, to create a simple badge that changes its background based on color mode, here's how to go about it:

import React from "react";
import {
  Button,
  Flex,
  useColorMode,
  extendTheme,
  useStyleConfig,
  forwardRef,
  chakra,
  HTMLChakraProps,
  ThemingProps
} from "@chakra-ui/react";
import { StyleConfig } from "@chakra-ui/theme-tools";

// 1. define component configuration
const components: Record<string, StyleConfig> = {
  CustomBadge: {
    baseStyle: ({ colorMode }) => ({
      bg: colorMode === "dark" ? "green.300" : "green.500",
      color: colorMode === "dark" ? "gray.800" : "white",
      textTransform: "uppercase",
      fontWeight: "semibold",
      letterSpacing: "0.02em",
      padding: "4px",
      borderRadius: "2px",
      fontSize: "12px"
    }),
    variants: {
      custom: ({ colorMode }) => ({
        bg: colorMode === "dark" ? "blue.200" : "blue.500",
        padding: "8px"
      })
    }
  }
};

// 2. Call 'extendTheme' and pass your custom values
export const customTheme = extendTheme({ components });

export interface CustomBadgeProps
  extends HTMLChakraProps<"span">,
    ThemingProps {}

// 3. Use it in your components
const CustomBadge = forwardRef<CustomBadgeProps, "span">((props, ref) => {
  const { size, variant, ...rest } = props;
  const styles = useStyleConfig("CustomBadge", { size, variant });

  return <chakra.span ref={ref} __css={styles} {...rest} />;
});

export default function App() {
  const { toggleColorMode } = useColorMode();
  return (
    <>
      <Flex
        height="100vh"
        direction="column"
        justifyContent="center"
        alignItems="center"
      >
        {/* Remove the variant to see the other custom styling */}
        <CustomBadge variant="custom">I am a custom badge</CustomBadge>
        <Button onClick={toggleColorMode} mt={6}>
          Toggle Color Mode
        </Button>
      </Flex>
    </>
  );
}

Multipart or Composite Component#

When it comes to multipart components for example tabs or menus etc, that have multiple sub-parts, you can also style them based on the color mode. Here's the signature:

type StyleInterpolation =
| { [part: string]: SystemStyleObject }
| ((options: StyleOptions) => { [part: string]: SystemStyleObject })
interface StyleOptions {
theme: Theme
colorMode: 'light' | 'dark'
colorScheme: string
}
interface StyleConfig {
baseStyle: StyleInterpolation
sizes: { [size: string]: StyleInterpolation }
variants: { [variant: string]: StyleInterpolation }
defaultProps?: {
variant: string
size: string
}
}

Distributing a Theme Package#

Publishing your theme to a package registry such as NPM is a great way to share your theme across multiple projects or applications.

A published theme package should export a theme object as either the default export or an export named theme. For example, in chakra-theme-package/src/index.js:

import { extendTheme } from '@chakra-ui/react'
const theme = extendTheme({})
// as default export
export default theme
// as named export
export { theme }

See this guide for more recommendations on how to structure your theme package.

Note ⚠️: If you're using TypeScript, you'll want to include some documentation guiding consumers of your theme package to add a postinstall script to generate typings for your theme. See the theme typings section for details.

Theme Typings#

v1.2.0

When adding new components, component variations, sizes, colors and other theme foundations, you can extend the internal theme typings to provide autocomplete for your application theme.

If you want to learn how to scale your custom theme you can follow this guide.

Install#

npm i -D @chakra-ui/cli

Usage#

For a theme file:

chakra-cli tokens <path/to/your/theme.(js|ts)>

or, for a theme package:

chakra-cli tokens <@your-org/chakra-theme-package>

The theme entrypoint file should export the theme object either as default export or as named theme export.

Note 🚨: If you delete the node_modules directory, you'll need to re-run the command to get proper typings again.

For convenience, you can add a postinstall script to your package.json, so you don't have to think about this every time you reinstall your dependencies.

"scripts": {
"gen:theme-typings": "chakra-cli tokens <path/to/your/theme.(js|ts)>",
"postinstall": "npm run gen:theme-typings"
},
"devDependencies": {
"@chakra-ui/cli": "^1.1.0"
}

The autocomplete for theme token only works in Visual Studio Code for now. We'd love to support JetBrains IDEs, but we have to wait for them to improve their TypeScript support.

Please note that the CLI cannot read non-JavaScript/TypeScript files. If you import other file types (.css, .woff or .svg) in your theme file, you'll need to move those imports out of the theme file.

Proudly made inNigeria by Segun Adebayo

Deployed by Vercel