Build faster with Premium Chakra UI Components 💎
Learn moreApril 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).
Start by installing the React version of Ark UI:
npm install @ark-ui/react
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:
Root
: The root component of the carouselItem
: The item component of the carouselPrevTrigger
: The previous trigger component of the carouselNextTrigger
: The next trigger component of the carouselEach 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>
)
}
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,
}
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.