Claude Code for Ark UI — Workflow Guide

Written by Michael Lip · Solo founder of Zovo · $400K+ on Upwork · 100% JSS Join 50+ builders · More at zovo.one

The Setup

You are building accessible, unstyled UI components with Ark UI, a headless component library from the creators of Chakra UI built on top of Zag.js state machines. Ark UI provides components for React, Solid, and Vue with built-in accessibility and complex interaction patterns. Claude Code can generate Ark UI components, but it defaults to Chakra UI or Radix patterns that differ from Ark UI’s API.

What Claude Code Gets Wrong By Default

  1. Uses Chakra UI prop-based styling. Claude writes <Button colorScheme="blue" size="lg">. Ark UI is headless — it provides behavior and accessibility without styling. You style components yourself with CSS, Tailwind, or Panda CSS.

  2. Imports from @chakra-ui/react. Claude imports Chakra components instead of Ark UI. Ark UI uses @ark-ui/react, @ark-ui/solid, or @ark-ui/vue depending on your framework.

  3. Ignores the compound component pattern. Claude renders <Select options={[...]} /> as a single component. Ark UI uses compound components: <Select.Root>, <Select.Trigger>, <Select.Content>, <Select.Item> — each part is individually styleable.

  4. Skips the Context API for state access. Claude manages state externally with useState. Ark UI exposes component state through context — <Select.Context> provides access to the current value, open state, and methods without lifting state.

The CLAUDE.md Configuration

# Ark UI Project

## Components
- Library: Ark UI (@ark-ui/react, @ark-ui/solid, or @ark-ui/vue)
- Style: Headless — no built-in styles
- State: Zag.js state machines under the hood
- Accessibility: Built-in ARIA, keyboard nav, focus management

## Ark UI Rules
- Import from @ark-ui/react (or /solid, /vue)
- Compound components: Root, Trigger, Content, Item pattern
- Use Context component to access internal state
- Style with CSS/Tailwind/Panda CSS — Ark provides no styles
- asChild prop to render as custom element
- onValueChange, onOpenChange for controlled callbacks
- Presence component for enter/exit animations

## Conventions
- Each component has Root wrapper: <Dialog.Root>, <Select.Root>
- Trigger/Content/Item subcomponents for each part
- Use asChild to forward props to custom styled elements
- Controlled: value + onValueChange props on Root
- Uncontrolled: defaultValue prop on Root
- Animation: use <Presence> with CSS transitions
- Park UI or custom design system for styled versions

Workflow Example

You want to build an accessible combobox with search filtering. Prompt Claude Code:

“Create a searchable combobox using Ark UI for selecting a country. Include keyboard navigation, filtering as the user types, and custom styling with Tailwind CSS. Use the compound component pattern.”

Claude Code should import from @ark-ui/react, create <Combobox.Root> with <Combobox.Input>, <Combobox.Trigger>, <Combobox.Content>, and <Combobox.Item> subcomponents, add Tailwind classes to each part, and handle filtering through onInputValueChange with state-driven item filtering.

Common Pitfalls

  1. Mixing Ark UI with Chakra UI imports. Claude imports some components from Chakra and others from Ark UI. These are separate libraries with different APIs. Use Ark UI exclusively or Chakra exclusively — do not mix them in the same component tree.

  2. Missing Portal for dropdowns. Claude renders Select or Combobox content inline. Ark UI provides <Select.Positioner> and Portal support for proper layering. Without portaling, dropdown content can be clipped by parent overflow.

  3. Forgetting animation with Presence. Claude conditionally renders content with {isOpen && <Content>}. Ark UI supports exit animations through the <Presence> component — direct conditional rendering skips exit animations entirely.