Introduction to Chakra UI
Chakra UI is a simple, modular, and accessible component library that gives you the building blocks to create React applications with speed and consistency. It provides a set of professionally designed, composable, and reusable components built with accessibility in mind. Chakra UI matters because it combines the best practices of style systems like Tailwind with the convenience of component libraries like Material UI, all while maintaining a small bundle size and excellent developer experience.
Core Concepts and Principles
Style System Fundamentals
- Theme-Based: All components use values from a centralized theme
- Responsive Styles: Built-in responsive design system
- Component Composition: Components can be combined and nested
- Style Props: Inline styling with shorthand props
- Color Mode: Built-in light and dark mode support
- Accessibility: ARIA compliant with keyboard navigation
Style Props
Style props allow you to pass styles directly to components as props:
Category | Props | Example |
---|---|---|
Margin | m, mt, mr, mb, ml, mx, my | <Box m="4" mt="2"> |
Padding | p, pt, pr, pb, pl, px, py | <Box p="4" px="6"> |
Color | color, bg, bgColor, opacity | <Text color="blue.500"> |
Typography | fontSize, fontWeight, letterSpacing | <Text fontSize="xl"> |
Layout | width, height, display, minW, maxW | <Box w="100%" maxW="500px"> |
Flexbox | flex, flexDirection, justify, align | <Flex justify="center"> |
Grid | gridGap, gridColumn, gridRow | <Grid gridGap="4"> |
Border | border, borderWidth, borderRadius | <Box borderRadius="md"> |
Responsive Design System
Chakra UI uses array syntax for responsive styles:
// This sets different margins for different breakpoints
<Box m={[2, 4, 6, 8]}>
Responsive margin
</Box>
// This is equivalent to:
// base: margin: 8px
// sm: margin: 16px
// md: margin: 24px
// lg: margin: 32px
You can also use object syntax:
<Box
width={{
base: "100%", // 0-479px
sm: "80%", // 480-767px
md: "60%", // 768-991px
lg: "40%", // 992-1279px
xl: "30%" // 1280px+
}}
>
Responsive width
</Box>
Setup and Installation
Basic Setup with Create React App
# Create a new React app
npx create-react-app my-chakra-app
cd my-chakra-app
# Install Chakra UI and its peer dependencies
npm i @chakra-ui/react @emotion/react @emotion/styled framer-motion
Setup with Next.js
# Create a new Next.js app
npx create-next-app my-chakra-next-app
cd my-chakra-next-app
# Install Chakra UI and its peer dependencies
npm i @chakra-ui/react @emotion/react @emotion/styled framer-motion
Provider Setup
// App.js or _app.js (for Next.js)
import { ChakraProvider } from '@chakra-ui/react'
function MyApp({ Component, pageProps }) {
return (
<ChakraProvider>
<Component {...pageProps} />
</ChakraProvider>
)
}
export default MyApp
Custom Theme Setup
// theme.js
import { extendTheme } from '@chakra-ui/react'
const theme = extendTheme({
colors: {
brand: {
100: "#f7fafc",
500: "#3182ce",
900: "#1a365d",
},
},
fonts: {
heading: 'Montserrat, sans-serif',
body: 'Inter, system-ui, sans-serif',
},
fontWeights: {
normal: 400,
medium: 500,
bold: 700,
},
breakpoints: {
sm: '480px',
md: '768px',
lg: '992px',
xl: '1280px',
'2xl': '1536px',
},
components: {
Button: {
// Custom variants
variants: {
solid: {
bg: 'brand.500',
color: 'white',
_hover: {
bg: 'brand.600',
},
},
},
},
},
})
export default theme
// Import and use the theme
import theme from './theme'
function MyApp({ Component, pageProps }) {
return (
<ChakraProvider theme={theme}>
<Component {...pageProps} />
</ChakraProvider>
)
}
Layout Components
Box
The fundamental building block:
<Box
bg="gray.50"
p={4}
color="gray.700"
borderRadius="md"
boxShadow="md"
>
This is a Box
</Box>
Flex
Flex container with built-in flexbox properties:
<Flex
direction={{ base: "column", md: "row" }}
align="center"
justify="space-between"
wrap="wrap"
p={4}
bg="gray.100"
>
<Box p={2}>Item 1</Box>
<Box p={2}>Item 2</Box>
<Box p={2}>Item 3</Box>
</Flex>
Grid
CSS Grid container:
<Grid
templateColumns={{
base: "repeat(1, 1fr)",
md: "repeat(2, 1fr)",
lg: "repeat(3, 1fr)"
}}
gap={6}
p={4}
>
<Box bg="tomato" p={4}>Item 1</Box>
<Box bg="blue.300" p={4}>Item 2</Box>
<Box bg="green.300" p={4}>Item 3</Box>
<Box bg="yellow.300" p={4}>Item 4</Box>
</Grid>
SimpleGrid
Simplified responsive grid system:
<SimpleGrid
columns={{ base: 1, md: 2, lg: 3 }}
spacing={10}
>
<Box bg="tomato" p={4}>Item 1</Box>
<Box bg="blue.300" p={4}>Item 2</Box>
<Box bg="green.300" p={4}>Item 3</Box>
</SimpleGrid>
Container
Centers content with a max-width:
<Container maxW="container.md" p={4}>
Centered content with a max-width
</Container>
Stack
Stack children in horizontal or vertical direction:
// Vertical stack
<VStack
spacing={4}
align="stretch"
>
<Box bg="red.200" p={4}>Item 1</Box>
<Box bg="green.200" p={4}>Item 2</Box>
<Box bg="blue.200" p={4}>Item 3</Box>
</VStack>
// Horizontal stack
<HStack spacing={4}>
<Box bg="red.200" p={4}>Item 1</Box>
<Box bg="green.200" p={4}>Item 2</Box>
<Box bg="blue.200" p={4}>Item 3</Box>
</HStack>
Center
Center child elements:
<Center h="200px" color="white" bg="blue.500">
This is centered
</Center>
Typography Components
Text
For paragraphs and spans:
<Text
fontSize={{ base: "md", md: "lg" }}
fontWeight="medium"
color="gray.700"
lineHeight="tall"
>
This is a text component
</Text>
Heading
For headings:
<Heading
as="h1"
size="xl"
color="blue.500"
textAlign="center"
mb={4}
>
Main Heading
</Heading>
<Heading as="h2" size="lg" mb={2}>Subheading</Heading>
<Heading as="h3" size="md" mb={2}>Section Heading</Heading>
LinkText
For hyperlinks:
<Link
color="teal.500"
href="https://chakra-ui.com"
isExternal
_hover={{ textDecoration: "none", color: "teal.700" }}
>
Chakra UI Website
</Link>
Form Components
Button
Basic button component:
<Button
colorScheme="blue"
size="md"
variant="solid"
leftIcon={<EmailIcon />}
isLoading={false}
loadingText="Submitting"
onClick={() => console.log('Button clicked')}
_hover={{ bg: "blue.600" }}
>
Submit
</Button>
Button variants and sizes:
// Variants
<Button variant="solid">Solid</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="link">Link</Button>
// Sizes
<Button size="xs">XS</Button>
<Button size="sm">SM</Button>
<Button size="md">MD</Button>
<Button size="lg">LG</Button>
Input
Text input field:
<Input
placeholder="Enter email"
type="email"
size="md"
variant="outline"
focusBorderColor="blue.500"
errorBorderColor="red.500"
isRequired
isInvalid={errors.email}
/>
With form control and label:
<FormControl isRequired isInvalid={errors.email}>
<FormLabel htmlFor="email">Email</FormLabel>
<Input
id="email"
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<FormHelperText>
We'll never share your email.
</FormHelperText>
<FormErrorMessage>
{errors.email}
</FormErrorMessage>
</FormControl>
Select
Dropdown selection:
<Select
placeholder="Select option"
variant="filled"
onChange={(e) => setValue(e.target.value)}
>
<option value="option1">Option 1</option>
<option value="option2">Option 2</option>
<option value="option3">Option 3</option>
</Select>
Checkbox
Checkbox component:
<Checkbox
isChecked={checked}
onChange={(e) => setChecked(e.target.checked)}
colorScheme="green"
size="lg"
>
I agree to terms
</Checkbox>
// Checkbox group
<CheckboxGroup
colorScheme="blue"
defaultValue={["one", "three"]}
onChange={setCheckedItems}
>
<Stack spacing={2} direction="column">
<Checkbox value="one">One</Checkbox>
<Checkbox value="two">Two</Checkbox>
<Checkbox value="three">Three</Checkbox>
</Stack>
</CheckboxGroup>
Radio
Radio buttons:
<RadioGroup onChange={setValue} value={value} defaultValue="1">
<Stack direction="column">
<Radio value="1" colorScheme="red">Option 1</Radio>
<Radio value="2" colorScheme="green">Option 2</Radio>
<Radio value="3" colorScheme="blue">Option 3</Radio>
</Stack>
</RadioGroup>
Switch
Toggle switch:
<Switch
isChecked={isChecked}
onChange={(e) => setIsChecked(e.target.checked)}
colorScheme="teal"
size="lg"
/>
<FormControl display="flex" alignItems="center">
<FormLabel htmlFor="dark-mode" mb="0">
Enable Dark Mode
</FormLabel>
<Switch id="dark-mode" colorScheme="purple" />
</FormControl>
Textarea
Multiline text input:
<Textarea
placeholder="Enter your message"
value={message}
onChange={(e) => setMessage(e.target.value)}
size="md"
resize="vertical"
rows={4}
/>
NumberInput
For numeric input:
<NumberInput
defaultValue={15}
min={10}
max={30}
step={1}
precision={0}
onChange={(valueString) => setValue(parseInt(valueString))}
>
<NumberInputField />
<NumberInputStepper>
<NumberIncrementStepper />
<NumberDecrementStepper />
</NumberInputStepper>
</NumberInput>
Slider
Range slider:
<Slider
defaultValue={60}
min={0}
max={100}
step={1}
onChange={(v) => setValue(v)}
colorScheme="teal"
>
<SliderTrack>
<SliderFilledTrack />
</SliderTrack>
<SliderThumb />
</Slider>
PinInput
For verification codes:
<PinInput otp size="lg" onChange={(value) => setPinValue(value)}>
<PinInputField />
<PinInputField />
<PinInputField />
<PinInputField />
</PinInput>
Feedback Components
Alert
For important messages:
<Alert
status="success"
variant="subtle"
flexDirection="row"
alignItems="center"
justifyContent="center"
textAlign="center"
height="200px"
>
<AlertIcon boxSize="40px" mr={0} />
<AlertTitle mt={4} mb={1} fontSize="lg">
Application submitted!
</AlertTitle>
<AlertDescription maxWidth="sm">
Thanks for submitting your application. Our team will get back to you soon.
</AlertDescription>
</Alert>
// Status variants: "info", "warning", "success", "error", "loading"
Toast
Temporary notification:
function ToastExample() {
const toast = useToast()
return (
<Button
onClick={() =>
toast({
title: "Account created.",
description: "We've created your account for you.",
status: "success",
duration: 9000,
isClosable: true,
position: "top-right",
})
}
>
Show Toast
</Button>
)
}
Progress
Progress indicators:
// Linear progress
<Progress value={80} colorScheme="green" size="lg" />
// Circular progress
<CircularProgress value={40} color="green.400" thickness="4px">
<CircularProgressLabel>40%</CircularProgressLabel>
</CircularProgress>
// Indeterminate progress
<Progress size="xs" isIndeterminate />
Skeleton
Loading placeholder:
<Skeleton height="20px" />
<Skeleton height="40px" mt={2} />
<Skeleton height="60px" mt={2} />
// With isLoaded prop
<Skeleton isLoaded={isLoaded}>
<Text>This content will appear when loaded</Text>
</Skeleton>
// With fadeDuration
<SkeletonText mt="4" noOfLines={4} spacing="4" skeletonHeight="2" fadeDuration={1} />
Spinner
Loading spinner:
<Spinner
thickness="4px"
speed="0.65s"
emptyColor="gray.200"
color="blue.500"
size="xl"
/>
Data Display Components
Badge
For status indicators or counts:
<Badge colorScheme="green">Success</Badge>
<Badge colorScheme="red">Error</Badge>
<Badge colorScheme="purple" variant="outline">Outline</Badge>
<Badge colorScheme="teal" variant="solid">Solid</Badge>
// With an icon
<Badge colorScheme="green">
<Icon as={CheckIcon} mr={1} />
Verified
</Badge>
Tag
Similar to badges but for filtering:
<Tag size="lg" colorScheme="red" borderRadius="full">
<TagLabel>Sample Tag</TagLabel>
<TagCloseButton onClick={() => console.log('Tag removed')} />
</Tag>
List
List component with various styles:
<List spacing={3}>
<ListItem>
<ListIcon as={CheckCircleIcon} color="green.500" />
Item 1
</ListItem>
<ListItem>
<ListIcon as={CheckCircleIcon} color="green.500" />
Item 2
</ListItem>
<ListItem>
<ListIcon as={WarningIcon} color="red.500" />
Item 3
</ListItem>
</List>
Table
Data tables:
<TableContainer>
<Table variant="simple" colorScheme="teal">
<TableCaption>Imperial to metric conversion factors</TableCaption>
<Thead>
<Tr>
<Th>Item</Th>
<Th isNumeric>Multiply by</Th>
<Th>To convert</Th>
</Tr>
</Thead>
<Tbody>
<Tr>
<Td>inches</Td>
<Td isNumeric>25.4</Td>
<Td>millimeters</Td>
</Tr>
<Tr>
<Td>feet</Td>
<Td isNumeric>30.48</Td>
<Td>centimeters</Td>
</Tr>
</Tbody>
<Tfoot>
<Tr>
<Th>Item</Th>
<Th isNumeric>Multiply by</Th>
<Th>To convert</Th>
</Tr>
</Tfoot>
</Table>
</TableContainer>
Stat
For displaying statistics:
<Stat>
<StatLabel>Collected Fees</StatLabel>
<StatNumber>£0.00</StatNumber>
<StatHelpText>Feb 12 - Feb 28</StatHelpText>
</Stat>
// With indicators
<StatGroup>
<Stat>
<StatLabel>Sent</StatLabel>
<StatNumber>345,670</StatNumber>
<StatHelpText>
<StatArrow type="increase" />
23.36%
</StatHelpText>
</Stat>
<Stat>
<StatLabel>Clicked</StatLabel>
<StatNumber>45</StatNumber>
<StatHelpText>
<StatArrow type="decrease" />
9.05%
</StatHelpText>
</Stat>
</StatGroup>
Code
For displaying code:
<Code>console.log("Hello, world!");</Code>
// With color schemes
<Code colorScheme="red">Error code: 404</Code>
<Code colorScheme="green">Success code: 200</Code>
Kbd
For keyboard shortcuts:
<span>
<Kbd>shift</Kbd> + <Kbd>H</Kbd>
</span>
Disclosure Components
Accordion
Collapsible panels:
<Accordion allowMultiple>
<AccordionItem>
<h2>
<AccordionButton>
<Box flex="1" textAlign="left">
Section 1 title
</Box>
<AccordionIcon />
</AccordionButton>
</h2>
<AccordionPanel pb={4}>
Section 1 content
</AccordionPanel>
</AccordionItem>
<AccordionItem>
<h2>
<AccordionButton>
<Box flex="1" textAlign="left">
Section 2 title
</Box>
<AccordionIcon />
</AccordionButton>
</h2>
<AccordionPanel pb={4}>
Section 2 content
</AccordionPanel>
</AccordionItem>
</Accordion>
Tabs
Tabbed interface:
<Tabs variant="enclosed" colorScheme="teal">
<TabList>
<Tab>Profile</Tab>
<Tab>Settings</Tab>
<Tab>Messages</Tab>
</TabList>
<TabPanels>
<TabPanel>
<p>Profile content!</p>
</TabPanel>
<TabPanel>
<p>Settings content!</p>
</TabPanel>
<TabPanel>
<p>Messages content!</p>
</TabPanel>
</TabPanels>
</Tabs>
// Variants: "line", "enclosed", "enclosed-colored", "soft-rounded", "solid-rounded", "unstyled"
Modal
Dialogs and modals:
function BasicModal() {
const { isOpen, onOpen, onClose } = useDisclosure()
return (
<>
<Button onClick={onOpen}>Open Modal</Button>
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader>Modal Title</ModalHeader>
<ModalCloseButton />
<ModalBody>
Content of the modal goes here.
</ModalBody>
<ModalFooter>
<Button colorScheme="blue" mr={3} onClick={onClose}>
Close
</Button>
<Button variant="ghost">Secondary Action</Button>
</ModalFooter>
</ModalContent>
</Modal>
</>
)
}
Drawer
Sliding panels:
function DrawerExample() {
const { isOpen, onOpen, onClose } = useDisclosure()
const [placement, setPlacement] = React.useState("right")
return (
<>
<Button colorScheme="blue" onClick={onOpen}>
Open Drawer
</Button>
<Drawer placement={placement} onClose={onClose} isOpen={isOpen}>
<DrawerOverlay />
<DrawerContent>
<DrawerHeader borderBottomWidth="1px">Basic Drawer</DrawerHeader>
<DrawerBody>
<p>Some contents...</p>
</DrawerBody>
<DrawerFooter>
<Button variant="outline" mr={3} onClick={onClose}>
Cancel
</Button>
<Button colorScheme="blue">Save</Button>
</DrawerFooter>
</DrawerContent>
</Drawer>
</>
)
}
Popover
Small floating content panels:
<Popover>
<PopoverTrigger>
<Button>Trigger</Button>
</PopoverTrigger>
<PopoverContent>
<PopoverArrow />
<PopoverCloseButton />
<PopoverHeader>Confirmation!</PopoverHeader>
<PopoverBody>Are you sure you want to continue?</PopoverBody>
<PopoverFooter d="flex" justifyContent="flex-end">
<ButtonGroup size="sm">
<Button variant="outline">Cancel</Button>
<Button colorScheme="red">Apply</Button>
</ButtonGroup>
</PopoverFooter>
</PopoverContent>
</Popover>
Tooltip
Information on hover:
<Tooltip label="Hey, I'm here!" aria-label="A tooltip">
Hover me
</Tooltip>
// With placement
<Tooltip hasArrow label="Search places" placement="top">
<IconButton
aria-label="Search database"
icon={<SearchIcon />}
/>
</Tooltip>
Navigation Components
Menu
Dropdown menus:
<Menu>
<MenuButton as={Button} rightIcon={<ChevronDownIcon />}>
Actions
</MenuButton>
<MenuList>
<MenuItem>Download</MenuItem>
<MenuItem>Create a Copy</MenuItem>
<MenuItem>Mark as Draft</MenuItem>
<MenuDivider />
<MenuItem color="red.400">Delete</MenuItem>
</MenuList>
</Menu>
// With icons
<Menu>
<MenuButton as={Button}>
Menu with icons
</MenuButton>
<MenuList>
<MenuItem icon={<AddIcon />}>New File</MenuItem>
<MenuItem icon={<ExternalLinkIcon />}>Open</MenuItem>
<MenuItem icon={<RepeatIcon />}>Save</MenuItem>
<MenuItem icon={<EditIcon />}>Edit</MenuItem>
</MenuList>
</Menu>
Breadcrumb
Navigation breadcrumbs:
<Breadcrumb separator="/">
<BreadcrumbItem>
<BreadcrumbLink href="#">Home</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbItem>
<BreadcrumbLink href="#">Docs</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbItem isCurrentPage>
<BreadcrumbLink href="#">Components</BreadcrumbLink>
</BreadcrumbItem>
</Breadcrumb>
// With custom separator
<Breadcrumb separator=">">
<BreadcrumbItem>
<BreadcrumbLink href="#">Home</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbItem isCurrentPage>
<BreadcrumbLink href="#">About</BreadcrumbLink>
</BreadcrumbItem>
</Breadcrumb>
Link
For navigation links:
<Link href="https://chakra-ui.com" isExternal>
Chakra UI <ExternalLinkIcon mx="2px" />
</Link>
Media Components
Image
Display images:
<Image
src="https://bit.ly/dan-abramov"
alt="Dan Abramov"
width="200px"
height="200px"
borderRadius="full"
objectFit="cover"
fallback={<Spinner />}
/>
Avatar
User avatars:
<Avatar name="Dan Abrahmov" src="https://bit.ly/dan-abramov" />
// Avatar with badge
<AvatarGroup>
<Avatar name="Ryan Florence" src="https://bit.ly/ryan-florence" />
<Avatar name="Segun Adebayo" src="https://bit.ly/sage-adebayo" />
<Avatar name="Kent Dodds" src="https://bit.ly/kent-c-dodds" />
<Avatar name="Prosper Otemuyiwa" src="https://bit.ly/prosper-baba" />
<Avatar name="Christian Nwamba" src="https://bit.ly/code-beast" />
</AvatarGroup>
Icon
SVG icons:
// Using built-in icons
<Icon as={FaUser} boxSize={6} color="red.500" />
// Custom icon
<Icon
width="24px"
height="24px"
viewBox="0 0 24 24"
color="blue.500"
>
<path
fill="currentColor"
d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"
/>
</Icon>
Overlay Components
AlertDialog
Confirmation dialogs:
function AlertDialogExample() {
const [isOpen, setIsOpen] = React.useState(false)
const onClose = () => setIsOpen(false)
const cancelRef = React.useRef()
return (
<>
<Button colorScheme="red" onClick={() => setIsOpen(true)}>
Delete Customer
</Button>
<AlertDialog
isOpen={isOpen}
leastDestructiveRef={cancelRef}
onClose={onClose}
>
<AlertDialogOverlay>
<AlertDialogContent>
<AlertDialogHeader fontSize="lg" fontWeight="bold">
Delete Customer
</AlertDialogHeader>
<AlertDialogBody>
Are you sure? You can't undo this action afterwards.
</AlertDialogBody>
<AlertDialogFooter>
<Button ref={cancelRef} onClick={onClose}>
Cancel
</Button>
<Button colorScheme="red" onClick={onClose} ml={3}>
Delete
</Button>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialogOverlay>
</AlertDialog>
</>
)
}
Common Hooks
useDisclosure
Manage disclosure state (open/close):
function Component() {
const { isOpen, onOpen, onClose, onToggle } = useDisclosure()
return (
<>
<Button onClick={onOpen}>Open Drawer</Button>
<Drawer isOpen={isOpen} onClose={onClose}>
<DrawerOverlay />
<DrawerContent>
<DrawerHeader>Drawer Example</DrawerHeader>
<DrawerBody>Some content</DrawerBody>
</DrawerContent>
</Drawer>
</>
)
}
useColorMode
Toggle between light and dark modes:
function ColorModeToggle() {
const { colorMode, toggleColorMode } = useColorMode()
return (
<Button onClick={toggleColorMode}>
Toggle {colorMode === "light" ? "Dark" : "Light"} Mode
</Button>
)
}
useBreakpointValue
Responsive value based on breakpoint:
function ResponsiveComponent() {
const variant = useBreakpointValue({
base: "solid",
md: "outline",
lg: "ghost"
})
return <Button variant={variant}>Click me</Button>
}
useToast
Create toast notifications:
function ToastExample() {
const toast = useToast()
return (
<Button
onClick={() =>
toast({
title: "Account created.",
description: "We've created your account for you.",
status: "success",
duration: 5000,
isClosable: true,
position: "top-right"
})
}
>
Show Toast
</Button>
)
}
Best Practices
Performance Optimization
- Use
shouldWrapChildren
prop to avoid unnecessary DOM nesting - Memoize components with
React.memo
when appropriate - Use
isLazy
prop on complex components like Modal and Drawer when they’re conditionally rendered
Accessibility Best Practices
- Always provide
aria-label
for IconButton components - Use semantic HTML elements (Heading, Button, etc.)
- Keep correct heading hierarchy (h1, h2, h3)
- Ensure sufficient color contrast
- Provide text alternatives for non-text content
- Make keyboard navigation smooth
Dark Mode Support
// In your theme.js
const theme = extendTheme({
config: {
initialColorMode: "light",
useSystemColorMode: true,
},
styles: {
global: (props) => ({
body: {
bg: props.colorMode === "dark" ? "gray.800" : "white",
color: props.colorMode === "dark" ? "white" : "gray.800",
},
}),
},
})
// Component with conditional styling
function ConditionalComponent() {
const { colorMode } = useColorMode()
return (
<Box bg={colorMode === "dark" ? "gray.700" : "gray.100"} p={4}>
This box changes with color mode
</Box>
)
}
Resources for Further Learning
Official Documentation
Community Resources
Learning Paths
- Beginner: Start with layout components (Box, Flex, Grid)
- Intermediate: Build forms and complex layouts
- Advanced: Create custom components and themes
This comprehensive cheat sheet covers the essential components, hooks, and patterns for building applications with Chakra UI. Whether you’re just starting or looking to optimize your workflow, these examples will help you build accessible, responsive interfaces with speed and consistency.