Build faster with Premium Chakra UI Components 💎

Learn more

Styling External Libraries

April 1, 2025

In this guide, we'll learn how to style external libraries using Chakra UI's styling system.

With the rise of headless component libraries like Ark UI, Radix UI, etc. it's common to want to use them while styling with Chakra UI.

Let's assume we want to style the Carousel component from Ark UI (an headless component library).

Install Ark UI

Start by installing the React version of Ark UI:

npm install @ark-ui/react

Understand the Component Anatomy

Ark UI breaks each headless component into smaller, functional parts. For example, some parts of a (carousel)[https://ark-ui.com/react/docs/components/carousel#anatomy] would be:

Each part is flexible and can be styled independently. Once you know what each one does, it becomes easier to add custom styles to the parts.

import { Carousel } from "@ark-ui/react/carousel"

const images = Array.from(
  { length: 5 },
  (_, i) => `https://picsum.photos/seed/${i + 1}/500/300`,
)

export const Demo = () => {
  return (
    <Carousel.Root defaultPage={0} slideCount={images.length}>
      <Carousel.Control>
        <Carousel.PrevTrigger>Previous</Carousel.PrevTrigger>
        <Carousel.NextTrigger>Next</Carousel.NextTrigger>
      </Carousel.Control>
      <Carousel.IndicatorGroup>
        {images.map((_, index) => (
          <Carousel.Indicator key={index} index={index} />
        ))}
      </Carousel.IndicatorGroup>
      <Carousel.ItemGroup>
        {images.map((image, index) => (
          <Carousel.Item key={index} index={index}>
            <img src={image} alt={`Slide ${index}`} />
          </Carousel.Item>
        ))}
      </Carousel.ItemGroup>
    </Carousel.Root>
  )
}

Styling the primitives

One way you can easily style headless primitives is to wrap within the chakra factory.

With the factory, you can apply a style object or recipe to the component.

components/ui/carousel.tsx

import { Carousel as ArkCarousel } from "@ark-ui/react/carousel"
import { chakra } from "@chakra-ui/react"

const CarouselRoot = chakra(ArkCarousel.Root, {
  base: {
    display: "flex",
    flexDirection: "column",
    alignItems: "center",
  },

  variants: {},
})

const CarouselItem = chakra(ArkCarousel.Item, {
  base: {
    width: "100%",
    height: "100%",
  },
})

const CarouselIndicatorGroup = chakra(ArkCarousel.IndicatorGroup, {
  base: {
    display: "flex",
    gap: 2,
  },
})

const CarouselIndicator = chakra(ArkCarousel.Indicator, {
  base: {
    borderRadius: "full",
    bg: "bg.subtle",
    _selected: {
      bg: "teal.solid",
    },
  },
  variants: {
    size: {
      sm: {
        width: 3,
        height: 3,
      },
      md: {
        width: 4,
        height: 4,
      },
    },
  },
})

const CarouselItemGroup = chakra(ArkCarousel.ItemGroup, {
  base: {
    display: "flex",
    gap: 2,
  },
})

export const Carousel = {
  Root: CarouselRoot,
  IndicatorGroup: CarouselIndicatorGroup,
  Indicator: CarouselIndicator,
  ItemGroup: CarouselItemGroup,
  Item: CarouselItem,
  NextTrigger: ArkCarousel.NextTrigger,
  PrevTrigger: ArkCarousel.PrevTrigger,
}

Using the styled components

Now that we have the styled components, we can use them in our app.

For the PrevTrigger and NextTrigger components, we can render them as IconButton components from Chakra UI.

pages/index.tsx

import { Carousel } from "@/components/ui/carousel"
import { IconButton } from "@chakra-ui/react"
import { LuArrowLeft, LuArrowRight } from "react-icons/lu"

const images = Array.from(
  { length: 5 },
  (_, i) => `https://picsum.photos/seed/${i + 1}/500/300`,
)

export const Demo = () => {
  return (
    <Carousel.Root defaultPage={0} slideCount={images.length}>
      <Carousel.Control>
        <Carousel.PrevTrigger asChild>
          <IconButton>
            <LuArrowLeft />
          </IconButton>
        </Carousel.PrevTrigger>
        <Carousel.NextTrigger asChild>
          <IconButton>
            <LuArrowRight />
          </IconButton>
        </Carousel.NextTrigger>
      </Carousel.Control>
      <Carousel.IndicatorGroup>
        {images.map((_, index) => (
          <Carousel.Indicator key={index} index={index} />
        ))}
      </Carousel.IndicatorGroup>
      <Carousel.ItemGroup>
        {images.map((image, index) => (
          <Carousel.Item key={index} index={index}>
            <img src={image} alt={`Slide ${index}`} />
          </Carousel.Item>
        ))}
      </Carousel.ItemGroup>
    </Carousel.Root>
  )
}

And that's it! You've now styled a headless component library using Chakra UI.