git clone https://github.com/agents-inc/skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/agents-inc/skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/src/skills/web-ui-chakra-ui" ~/.claude/skills/agents-inc-skills-web-ui-chakra-ui-84214c && rm -rf "$T"
src/skills/web-ui-chakra-ui/SKILL.mdChakra UI v3 Patterns
Quick Guide: Chakra UI v3 is a composable, accessible React component library. Set up with
andcreateSystem(defaultConfig). Style via props (ChakraProvider,bg,p), not className. Components are composable by default (color,Dialog.Root). Theme with design tokens and recipes viaDialog.Content. Dark mode uses semantic tokens (defineConfig,bg.subtle) andfg.mutedcondition. Removed_darkandframer-motiondeps from v2 -- uses CSS animations and recipes instead.@emotion/styled
<critical_requirements>
CRITICAL: Before Using This Skill
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
, named constants)import type
(You MUST wrap your app with
where system is created via ChakraProvider value={system}
)createSystem(defaultConfig)
(You MUST use composable component patterns (
, Dialog.Root
) -- v3 removed closed component APIs)Dialog.Content
(You MUST use style props (
, bg
, p
) or the color
factory for styling -- not raw className strings)chakra
(You MUST prefer semantic tokens (
, bg.subtle
) or fg.muted
condition for dark mode -- avoid _dark
when tokens suffice)useColorModeValue
</critical_requirements>
Auto-detection: Chakra UI, @chakra-ui/react, ChakraProvider, createSystem, defaultConfig, chakra factory, style props, defineRecipe, defineSlotRecipe, colorPalette, semantic tokens, Ark UI
When to use:
- Building React applications with accessible, composable UI components
- Rapid prototyping with style props (inline CSS via props)
- Implementing design token-based theming with dark mode support
- Creating component variants with the recipe system
- Projects that value accessibility and keyboard navigation out of the box
When NOT to use:
- Projects already using another component library
- Projects requiring zero-runtime CSS (Chakra uses Emotion at runtime)
- Projects that need utility-class-first styling integration
- Extremely bundle-size-sensitive applications
Key patterns covered:
- Provider setup with
andcreateSystemChakraProvider - Style props for layout, spacing, color, and typography
- Responsive design with object and array syntax
- Theme customization with tokens, semantic tokens, and recipes
- Composable components (Dialog, Menu, Popover, Drawer)
- Form components with Field pattern
- Dark mode via semantic tokens and
condition_dark
factory for custom styled componentschakra
<philosophy>
Philosophy
Chakra UI v3 is built on three pillars: Ark UI (headless component logic and accessibility), Panda CSS-inspired APIs (design tokens and recipes, powered by Emotion at runtime), and Park UI (default design system). Components are composable by default -- you compose
Dialog.Root > Dialog.Content > Dialog.Body instead of passing everything as props to a single <Dialog>.
Key v3 principles:
- Composable over configurable -- compound components replace prop-heavy APIs
- Tokens over hardcoded values -- colors, spacing, radii reference design tokens
- Recipes over runtime styles -- variant-based styling replaces runtime theme functions
- Semantic tokens for dark mode --
adapts automatically, no conditional logicbg.subtle - CSS animations over JS -- removed framer-motion, uses native CSS for animations
What Chakra UI handles vs what other skills handle:
- Chakra UI: component structure, style props, design tokens, recipes, composition, accessibility
- Your form library: validation schemas, submission logic, form state management
- Your data layer: server state, caching, mutations
<patterns>
Core Patterns
Pattern 1: Provider Setup
Every Chakra v3 app needs
createSystem and ChakraProvider. Add @layer directive for proper CSS ordering.
// theme.ts import { createSystem, defaultConfig, defineConfig } from "@chakra-ui/react"; // Basic: use defaults export const system = createSystem(defaultConfig); // Custom: extend with your tokens const config = defineConfig({ theme: { tokens: { colors: { brand: { 50: { value: "#ffe5f1" }, 500: { value: "#d53f8c" }, 900: { value: "#521b41" }, }, }, }, }, }); export const system = createSystem(defaultConfig, config);
// app.tsx import { ChakraProvider } from "@chakra-ui/react"; import { system } from "./theme"; export function App({ children }: { children: React.ReactNode }) { return <ChakraProvider value={system}>{children}</ChakraProvider>; }
/* Required CSS layer directive */ @layer reset, base, tokens, recipes;
Why good:
createSystem merges your config with defaults, tokens become CSS variables, recipes generate atomic classes
See examples/core.md for framework-specific setup (SPA, SSR).
Pattern 2: Style Props
Style props are the primary way to style elements. They map directly to CSS properties with shorthand aliases and token values.
import { Box, Flex, Text } from "@chakra-ui/react"; // Style props with token values <Box bg="blue.500" color="white" p="4" rounded="md" shadow="lg"> Styled via props </Box> // Shorthand aliases <Box mt="4" // marginTop px="6" // paddingX (left + right) w="full" // width: 100% maxW="md" // maxWidth mx="auto" // marginX: auto (centering) /> // Layout with Flex <Flex gap="4" align="center" justify="between" wrap="wrap"> <Text fontSize="lg" fontWeight="bold">Title</Text> <Text color="fg.muted">Subtitle</Text> </Flex>
Why good: co-located styles, type-safe token values, responsive-ready, no separate CSS files
// BAD: using className strings with Chakra components <Box className="bg-blue-500 p-4 rounded-md">Wrong approach</Box>
Why bad: bypasses token system, no type safety, loses dark mode adaptation
See examples/core.md for complete style prop reference.
Pattern 3: Responsive Design
Use object syntax (recommended) or array syntax for responsive values. Mobile-first with
base as default.
// Object syntax (preferred) -- explicit breakpoint names <Box p={{ base: "4", md: "6", lg: "8" }} fontSize={{ base: "sm", md: "md", lg: "lg" }} display={{ base: "block", md: "flex" }} /> // Array syntax -- positional: [base, sm, md, lg, xl, 2xl] <Box p={["4", "4", "6", "6", "8"]} /> // Skip breakpoints with undefined <Text fontWeight={["medium", undefined, undefined, "bold"]} /> // Advanced: range targeting <Text fontWeight={{ mdToXl: "bold" }} /> // Visibility helpers <Box hideBelow="md">Desktop only</Box> <Box hideFrom="md">Mobile only</Box>
Why good: mobile-first approach, named breakpoints are self-documenting, range targeting avoids repetition
Pattern 4: Composable Components
v3 uses compound components with dot notation. All complex components follow
Root > Trigger > Content > ... pattern.
import { Dialog, Button } from "@chakra-ui/react"; // Composable dialog function ConfirmDialog() { return ( <Dialog.Root> <Dialog.Trigger asChild> <Button>Open</Button> </Dialog.Trigger> <Dialog.Backdrop /> <Dialog.Content> <Dialog.Header>Confirm Action</Dialog.Header> <Dialog.Body>Are you sure?</Dialog.Body> <Dialog.Footer> <Dialog.CloseTrigger asChild> <Button variant="outline">Cancel</Button> </Dialog.CloseTrigger> <Button colorPalette="red">Confirm</Button> </Dialog.Footer> </Dialog.Content> </Dialog.Root> ); }
// BAD: v2-style closed component API (removed in v3) <Modal isOpen={isOpen} onClose={onClose}> <ModalOverlay /> <ModalContent> <ModalHeader>Title</ModalHeader> <ModalBody>Content</ModalBody> </ModalContent> </Modal>
Why bad: v2 API removed in v3,
isOpen/onClose replaced by open/onOpenChange, separate imports replaced by dot notation
See examples/composable-components.md for Menu, Popover, Drawer, and controlled patterns.
Pattern 5: Recipes and Variants
Recipes define reusable component styles with variants. Use
defineRecipe for single-part, defineSlotRecipe for multi-part components.
import { defineRecipe } from "@chakra-ui/react"; const badgeRecipe = defineRecipe({ base: { display: "inline-flex", alignItems: "center", fontWeight: "medium", rounded: "full", }, variants: { variant: { solid: { bg: "colorPalette.500", color: "white" }, outline: { borderWidth: "1px", borderColor: "colorPalette.500" }, subtle: { bg: "colorPalette.100", color: "colorPalette.800" }, }, size: { sm: { px: "2", py: "0.5", fontSize: "xs" }, md: { px: "3", py: "1", fontSize: "sm" }, }, }, defaultVariants: { variant: "subtle", size: "sm" }, });
Register recipes in your system config via
defineConfig({ theme: { recipes: { badge: badgeRecipe } } }).
Use with
useRecipe hook or the chakra factory (recommended):
import { chakra } from "@chakra-ui/react"; const Badge = chakra("span", badgeRecipe); // Usage <Badge variant="solid" colorPalette="green" size="md"> Active </Badge>;
See examples/theming.md for slot recipes, custom tokens, and semantic tokens.
Pattern 6: Dark Mode
Chakra v3 uses semantic tokens that adapt to color mode automatically. No conditional logic needed.
// RECOMMENDED: semantic tokens -- adapt automatically <Box bg="bg.subtle" color="fg.default" borderColor="border.muted"> This adapts to light/dark mode automatically </Box> // Direct _dark condition for overrides <Box bg="white" _dark={{ bg: "gray.800" }}> Explicit dark mode override </Box> // Inline condition syntax <Box bg={{ base: "white", _dark: "gray.800" }}> Inline dark override </Box>
Setup requires
ColorModeProvider and the CLI snippet:
npx @chakra-ui/cli snippet add color-mode
import { ColorModeProvider } from "@/components/ui/color-mode"; import { ChakraProvider } from "@chakra-ui/react"; import { system } from "./theme"; function App({ children }: { children: React.ReactNode }) { return ( <ChakraProvider value={system}> <ColorModeProvider>{children}</ColorModeProvider> </ChakraProvider> ); }
Why good: semantic tokens are the cleanest approach,
_dark condition for one-offs, avoids useColorModeValue boilerplate when tokens cover the use case
See examples/theming.md for theme toggle component and semantic token reference.
Pattern 7: Form Components
Use
Field for form layout with labels, help text, and error messages. Works with any form library.
import { Field, Input, Button, Stack } from "@chakra-ui/react"; function LoginForm() { return ( <Stack gap="4"> <Field.Root required> <Field.Label>Email</Field.Label> <Input type="email" placeholder="you@example.com" /> <Field.HelperText>We will never share your email.</Field.HelperText> </Field.Root> <Field.Root required invalid={!!errors?.password}> <Field.Label>Password</Field.Label> <Input type="password" /> {errors?.password && ( <Field.ErrorMessage>{errors.password}</Field.ErrorMessage> )} </Field.Root> <Button type="submit" colorPalette="blue"> Sign In </Button> </Stack> ); }
Why good: Field is form-library-agnostic, provides accessible labels and error messaging, composable structure
See examples/core.md for more form patterns.
</patterns>Detailed Resources:
- examples/core.md - Provider setup, style props reference, layout components, form patterns
- examples/theming.md - Tokens, semantic tokens, recipes, slot recipes, dark mode
- examples/composable-components.md - Dialog, Menu, Popover, Drawer, controlled state
- reference.md - Decision frameworks, v2-to-v3 migration, anti-patterns
<red_flags>
RED FLAGS
High Priority Issues:
- Using v2 APIs --
/isOpen
props,onClose
,useDisclosure
withoutChakraProvider
prop,value
are all removedextendTheme - Missing
CSS directive -- without@layer
styles may not apply correctly@layer reset, base, tokens, recipes; - Importing
-- removed in v3; use CSS animations or Chakra's built-in motionframer-motion - Using
-- removed in v3; use@emotion/styled
factory or style props insteadchakra
Medium Priority Issues:
- Boolean props with
prefix --is
is nowisDisabled
,disabled
is nowisLoading
,loading
is nowisInvalidinvalid
prop on Stack -- renamed tospacing
to align with CSSgap- Importing icons from
-- removed in v3; use your preferred icon library@chakra-ui/icons - Using
when semantic tokens suffice -- preferuseColorModeValue
,bg.subtle
tokens orfg.muted
condition;_dark
still works but adds unnecessary boilerplateuseColorModeValue
Common Mistakes:
- Separate component imports --
is nowimport { ListItem }
via dot notationList.Item - Hardcoding color values -- use token values (
) or semantic tokens (blue.500
)colorPalette.500 - Not using
for composition -- theasChild
prop has limited support; useas
for polymorphismasChild - Missing
-- components silently fail without the provider contextChakraProvider
Gotchas & Edge Cases:
callback shape -- receivesonOpenChange
object, not a plain boolean:{ open: boolean }onOpenChange={(details) => setOpen(details.open)}- CSS layer order matters --
must be in your root CSS@layer reset, base, tokens, recipes; - Snippet system -- many "components" are CLI-generated snippets (
), not installed packagesnpx @chakra-ui/cli snippet add
prop -- swaps the entire color context for a component tree; affects all children usingcolorPalette
tokenscolorPalette.*
shortcut -- for zero-config, importdefaultSystem
directly instead of callingdefaultSystemcreateSystem
</red_flags>
<critical_reminders>
CRITICAL REMINDERS
All code must follow project conventions in CLAUDE.md
(You MUST wrap your app with
where system is created via ChakraProvider value={system}
)createSystem(defaultConfig)
(You MUST use composable component patterns (
, Dialog.Root
) -- v3 removed closed component APIs)Dialog.Content
(You MUST use style props (
, bg
, p
) or the color
factory for styling -- not raw className strings)chakra
(You MUST prefer semantic tokens (
, bg.subtle
) or fg.muted
condition for dark mode -- avoid _dark
when tokens suffice)useColorModeValue
Failure to follow these rules will produce broken v2-style code that does not work with Chakra UI v3.
</critical_reminders>