-
Changed Naming convention for boolean properties from
is<X>
to<x>
- isOpen -> open
- defaultIsOpen -> defaultOpen
- isDisabled -> disabled
- isInvalid -> invalid
- isRequired -> required
-
Introduce new
unstyled
prop to every component to allow for unstyled rendering of the component or its parts
We've removed the Hide
component in favor of hidding elements using the
hideFrom
media queries or explicitly setting display: none
on the element.
The Show
component is now used to explicitly render an element based on the
condition set it when
property. It doesn't rely on media queries.
You can combine the useMediaQuery()
hook and Show
to achieve the previous
Show
and Hide
components.
- Changed
spacing
togap
- Changed
spacingX
torowGap
- Changed
spacingY
tocolumnGap
- Remove
shouldWrapChildren
in favor of using theWrapItem
component explicitly
- Change
spacing
togap
We've removed the @chakra-ui/next-js
package in favor of using the asChild
prop for better flexibility.
To style the Next.js image component, you can use the asChild
prop on the
Box
component.
<Box asChild>
<NextImage />
</Box>
To style the Next.js link component, you can use the asChild
prop on the
<Link isExternal asChild>
<NextLink />
</Link>
We no longer infer the props from element passed via the as
prop. This caused
a lot of slow typing issues and complexity in the codebase.
Prefer to use the asChild
prop which offers better flexibility.
The
asChild
pattern is inspired by Radix UI.
Due to the simplification of the as
prop, we no longer provide a custom
forwardRef
.
Prefer to use forwardRef
from React directly.
Renamed all container
parts to root
. Kindly update your theme to reflect
- Removed
ControlBox
component - Removed
@chakra-ui/icons
package. Prefer to uselucide-react
orreact-icons
instead.
All root components and their respective types are now suffixed with <X>.Root
or <X>Root
Accordion
->Accordion.Root
AccordionProps
->AccordionRootProps
Checkbox
->Checkbox.Root
CheckboxProps
->CheckboxRootProps
- and so on...
- Rename
allowMultiple
tomultiple
- Rename
allowToggle
tocollapsible
- Rename
AccordionButton
toAccordion.Trigger
- Rename
AccordionPanel
toAccordion.Content
- Rename
AccordionIcon
toAccordion.Indicator
. To render a custom icon, you can use theAccordion.Indicator
component and pass the icon as children.
Before:
<Accordion>
<AccordionItem>
<AccordionButton>
<AccordionIcon />
</AccordionButton>
<AccordionPanel pb={4}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
commodo consequat.
</AccordionPanel>
</AccordionItem>
</Accordion>
After:
<Accordion.Root>
<Accordion.Item>
<Accordion.Trigger>
<Accordion.Indicator />
</Accordion.Trigger>
<Accordion.Content pb={4}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
commodo consequat.
</Accordion.Content>
</Accordion.Item>
</Accordion.Root>
Before:
<Avatar name="Christian Nwamba" src="https://bit.ly/code-beast" />
After:
<Avatar.Root name="Dan Abrahmov" src="https://bit.ly/dan-abramov">
<Avatar.Image />
<Avatar.Fallback />
</Avatar.Root>
- Explicitly render the
separator
viaBreadcrumb.Separator
. - Pass custom separator as children to the
Breadcrumb.Separator
component - Explicitly render list via
Breadcrumb.List
- Explicitly render the ellipsis via
Breadcrumb.Ellipsis
- To add
spacing
, set thegap
on the list element listProps
has been removed. Pass props directly toBreadcrumb.List
Before:
<Breadcrumb spacing="4">
<BreadcrumbItem>
<BreadcrumbLink as={Link} to="/home" replace>
Breadcrumb 1
</BreadcrumbLink>
</BreadcrumbItem>
</Breadcrumb>
After:
<Breadcrumb.Root>
<Breadcrumb.List spacing="4">
<Breadcrumb.Item>
<Breadcrumb.Link asChild>
<Link to="/home" replace>
Breadcrumb 1
</Link>
</Breadcrumb.Link>
</Breadcrumb.Item>
<Breadcrumb.Separator />
</Breadcrumb.List>
</Breadcrumb.Root>
- Checkbox icon is now
Checkbox.Indicator
and can be used to customize the checkbox icon in the checked and indeterminate state.
Before:
<Checkbox defaultChecked>My Checkbox</Checkbox>
After:
<Checkbox.Root defaultChecked>
<Checkbox.Control />
<Checkbox.Label>My Checkbox</Checkbox.Label>
</Checkbox.Root>
Before:
<Progress value={50} />
After:
<Progress.Root value={50}>
<Progress.Track>
<Progress.FilledTrack />
</Progress.Track>
<Progress.ValueText />
</Progress.Root>
-
ProgressLabel
is now assigned toProgress.ValueText
. This means the theme key for the label is nowvalueText
-
ProgressLabel
should now be used to provide a label for the progress bar
Before:
<CircularProgress value={50} />
After:
<CircularProgress.Root value={50}>
<CircularProgress.Circle>
<CircularProgress.Track />
<CircularProgress.FilledTrack />
</CircularProgress.Circle>
</CircularProgress.Root>
-
CircularProgressLabel
is now assigned toCircularProgress.ValueText
-
CircularProgressLabel
should now be used to provide a label for the progress bar
TagLeftIcon
andTagRightIcon
are removed in favor of rendering the icon directly inside theTag
component.
- Move
portalProps
toTooltip.Positioner
Before:
<Tooltip label="Hey there" hasArrow>
<Button>Hover me</Button>
</Tooltip>
After:
<Tooltip.Root placement="bottom">
<Tooltip.Trigger asChild>
<Button>Hover me</Button>
</Tooltip.Trigger>
<Tooltip.Positioner>
<Tooltip.Content>
<Tooltip.Arrow />
Hey there
</Tooltip.Content>
</Tooltip.Positioner>
</Tooltip.Root>
However, you can still get back to the legacy API by creating a custom component.
import { Tooltip } from "@chakra-ui/react"
export type CustomTooltipProps = Tooltip.RootProps & {
label?: string
hasArrow?: boolean
}
const CustomTooltip = (props: Props) => {
const { label, children, hasArrow, ...localProps } = props
const [rootProps, contentProps] = Tooltip.splitProps(localProps)
return (
<Tooltip.Root placement="bottom" {...rootProps}>
<Tooltip.Trigger asChild>
{isValidElement(children) ? children : <span>{children}</span>}
</Tooltip.Trigger>
<Tooltip.Content {...contentProps}>
{hasArrow && <Tooltip.Arrow />}
{label}
</Tooltip.Content>
</Tooltip.Root>
)
}
- Remove
closeOnMouseDown
, usecloseOnPointerDown
instead - Remove all
arrow*
props in favor of rendering theTooltip.Arrow
component
Form control has now been renamed to Field
to better reflect its purpose as an
element that represents a form field.
<Field.Root id="first-name" isRequired isInvalid>
<Field.Label>First name</Field.Label>
<Input placeholder="First Name" />
<Field.HelpText>Keep it very short and sweet!</Field.HelpText>
<Field.ErrorMessage>Your First name is invalid</Field.ErrorMessage>
</Field.Root>
HelperText has been renamed to Field.HelpText
for brevity.
-
Removed
focusBorderColor
anderrorBorderColor
, consider setting the--focus-color
and--error-color
css variables instead -
Renamed
SelectIcon
toSelect.Indicator
-
Move
value
andonChange
to theNativeSelect.Field
component
The Select
component has been renamed to NativeSelect
to better reflect its
purpose as a native select element, and give room for a custom select component.
The API has also changed significantly to make it more modular.
Before:
<Select color="red.400">
<option value="option1">Option 1</option>
<option value="option2">Option 2</option>
<option value="option3">Option 3</option>
</Select>
After:
<NativeSelect.Root>
<NativeSelect.Field color="pink.500" placeholder="Select option">
<option value="Option 1">Option 1</option>
<option value="Option 2">Option 2</option>
<option value="Option 3">Option 3</option>
</NativeSelect.Field>
<NativeSelect.Icon />
</NativeSelect.Root>
- The
Modal
component has been renamed toDialog
to better reflect its purpose as a dialog element. - Removed
containerProps
in favor of rendering theDialog.Positioner
component to better control this element. - Renamed
ModalOverlay
toDialog.Backdrop
Before:
<Modal>
<ModalOverlay />
<ModalContent>
<ModalHeader>Modal Title</ModalHeader>
<ModalCloseButton />
<ModalBody />
<ModalFooter />
</ModalContent>
</Modal>
After:
<Dialog.Root>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Header>Dialog Title</Dialog.Header>
<Dialog.CloseTrigger />
<Dialog.Body />
<Dialog.Footer />
</Dialog.Content>
</Dialog.Positioner>
</Dialog.Root>
- Same changes as
Dialog
above - Renamed
DrawerOverlay
toDrawer.Backdrop
We've removed the AlertDialog
component in favor of passing the
role="alertdialog"
to the Dialog
component.
-
PopoverTrigger
now renders abutton
by default. Use theasChild
to switch the trigger to a different element. -
PopoverAnchor
now renders aspan
by default. Use theasChild
to switch the anchor to a different element. -
Popover now requires the
Popover.Positioner
component to control the position of the popover. -
Removed
containerProps
in favor of rendering thePopover.Positioner
component
Before:
<Popover>
<PopoverTrigger>
<Button>Trigger</Button>
</PopoverTrigger>
<PopoverContent>
<PopoverArrow />
<PopoverCloseButton />
<PopoverHeader>Confirmation!</PopoverHeader>
<PopoverBody>Are you sure you want to have that milkshake?</PopoverBody>
</PopoverContent>
</Popover>
After:
<Popover.Root>
<Popover.Trigger asChild>
<Button>Trigger</Button>
</Popover.Trigger>
<Popover.Positioner>
<Popover.Content>
<Popover.Arrow />
<Popover.CloseTrigger />
<Popover.Header>Confirmation!</Popover.Header>
<Popover.Body>
<p>Are you sure you want to have that milkshake?</p>
<br />
<button>Yes</button>
<button>No</button>
</Popover.Body>
</Popover.Content>
</Popover.Positioner>
</Popover.Root>
The Button
component has been simplified to remove internal complexity.
isLoading
Removed isLoading
prop in favor of rendering Spinner
component
Before:
<Button isLoading colorScheme="blue">
Click me
</Button>
After:
<Button disabled colorPalette="blue">
<Spinner boxSize="1em" />
Click me
</Button>
Alternative approach to keep the content width but center the spinner:
<Button disabled variant="solid" colorPalette="blue">
<AbsoluteCenter>
<BeatLoader size={8} color="white" />
</AbsoluteCenter>
<Span opacity="0">Click me</Span>
</Button>
leftIcon and rightIcon
Removed leftIcon
and rightIcon
in favor of rendering an icon component
inlined with the button content.
To implement
iconSpacing
, you can use thegap
prop on theButton
component.
Before:
<Button leftIcon={<AddIcon />}>Click me</Button>
After:
<Button>
<AddIcon />
Click me
</Button>
Removed loadingText
in favor of updating the button content directly.
Before:
<Button isLoading loadingText="Submitting">
Click me
</Button>
After:
<Button isDisabled>
<Spinner boxSize="1em" />
Submitting
</Button>
Renamed all table components to better reflect their purpose. This also affects the theme keys.
- Renamed
TableContainer
toTable.Overflow
- Renamed
Td
toTable.Cell
- Renamed
Th
toTable.ColumnHeader
- Renamed
Tr
toTable.Row
- Renamed
Thead
toTable.Header
- Renamed
Tbody
toTable.Body
- Renamed
Tfoot
toTable.Footer
- Renamed
isNumeric
tonumeric
- Removed
rootProps
in favor of rendering theMenu.Positioner
component - Renamed
MenuButton
toMenu.Trigger
-
Removed
OrderedList
andUnorderedList
in favor of using theList
component with theas
prop. -
To change the list style type, you can use the
styleType
prop on theList
component.
We've added Em
, Strong
, Quote
and Span
components
The For
component is a new component that allows you to render a list of items
using a render prop.
import { For } from "@chakra-ui/react"
const Demo = () => {
return (
<For each={[1, 2, 3]} fallback={<div>No items</div>}>
{(item) => <div key={item}>{item}</div>}
</For>
)
}
The Bleed
component applied a negative margin to allow content to bleed out
into the surrounding layout.
export const Demo = () => (
<Box padding="4" borderWidth="1px">
<Bleed inline="4" bg="pink.100" padding="3">
Some bleed
</Bleed>
<Box padding="4">Inner text</Box>
</Box>
)
You can import components by leveraging the dot notation.
import { Accordion } from "@chakra-ui/react"
const Demo = () => {
return (
<Accordion.Root>
<Accordion.Item>
<Accordion.Trigger>Click me</Accordion.Trigger>
<Accordion.Content>Panel content</Accordion.Content>
</Accordion.Item>
</Accordion.Root>
)
}
Removed support for as
prop due to the type complexity involved.
Action: Replace asChild
in chakra
factory and existing components.
import { Button } from "@chakra-ui/react"
const Demo = () => {
return (
<Button asChild>
<a href="#">Child</a>
</Button>
)
}
The chakra
factory has been recipes to make it easier to style components
using recipes. Its API is inspired by Panda CSS and Stitches.
- Renamed
baseStyle
tobase
- Removed
variants
andsizes
in favor of defining them directly in thevariants
object - Removed
sx
and__css
in favor of using thecss
prop which can now take an array of styles, which will be merged together.
import { chakra } from "@chakra-ui/react"
const Alert = chakra("div", {
base: {
lineHeight: "1",
fontSize: "sm",
rounded: 4,
fontFamily: "Inter",
color: "white",
},
variants: {
variant: {
default: { bg: "gray" },
error: { bg: "red" },
success: { bg: "green" },
warning: { bg: "orange" },
},
sizes: {
sm: { paddingX: 10, paddingY: 5 },
md: { paddingX: 20, paddingY: 10 },
lg: { paddingX: 30, paddingY: 15 },
},
},
defaultVariants: {
variant: "default",
size: "md",
},
})
We've also removed support for functions in the theme object due to the performance implications.
Consider the following approach instead:
- Use the
data-*
attribute to store dynamic values and style them using CSS - Design the dynamic property/value in the recipe
- Leverage
compoundVariants
to create complex variants overrides
We've renamed useStyleConfig
to useRecipe
, and useMultiStyleConfig
to
useSlotRecipe
Before:
import { chakra, useStyleConfig } from "@chakra-ui/react"
function Alert(props) {
const elementProps = omitThemingProps(props)
const styles = useStyleConfig("Alert", props)
return <chakra.div {...elementProps} __css={styles} />
}
After:
import { chakra, useRecipe } from "@chakra-ui/react"
function Alert(props) {
const recipe = useRecipe("Alert", props.recipe)
const [variantProps, elementProps] = recipe.splitVariantProps(props)
return <chakra.div {...elementProps} css={recipe(variantProps)} />
}
Before:
import { chakra, useMultiStyleConfig } from "@chakra-ui/react"
function Alert(props) {
const elementProps = omitThemingProps(props)
const styles = useMultiStyleConfig("Alert", props)
return (
<chakra.div __css={styles.root}>
<chakra.p __css={styles.title}>Welcome</chakra.p>
</chakra.div>
)
}
After:
import { chakra, useSlotRecipe } from "@chakra-ui/react"
function Alert(props) {
const recipe = useSlotRecipe("Alert", props.recipe)
const [variantProps, elementProps] = recipe.splitVariantProps(props)
const styles = recipe(variantProps)
return (
<chakra.div css={styles.root}>
<chakra.p css={styles.title}>Welcome</chakra.p>
</chakra.div>
)
}
TODO
Prefer to use useChakraContext
instead of useTheme
to access the theme and
much more.
- Changed to
RecipeProps
andSlotRecipeProps
for better clarity
- No more
ButtonGroup
, prefer to use the genericGroup
component instead - No more
InputGroup
, prefer genericGroup
andAddon
components - No more
InputLeftAddon
andInputRightAddon
, prefer to useAddon
component withplacement
prop
- Remove isRound in favor of passing
shape=pill
- Prefer to use
children
overicon
prop
- Added new
Blockquote
component - Docs: https://designsystem.utah.gov/library/components/textLayout/blockQuote
- Remove
max
prop in favor of userland control - Remove excess label part
- Move image related props to
Avatar.Image
component - Move fallback icon to
Avatar.Fallback
component - Move
name
prop toAvatar.Fallback
component
We're removed the storybook addon in favor of using @storybook/addon-themes
and withThemeByClassName
helper.
- No more
InputLeftAddon
andInputRightAddon
, prefer to useInputAddon
component with theGroup
component
- No more
InputLeftElement
andInputRightElement
, prefer to useInputElement
component with theGroup
component andplacement
prop.
- No more
InputGroup
, prefer genericGroup
component
- Removed
requiredIndicator
andoptionalIndicator
in favor of using theFormLabel.RequiredIndicator
with thefallback
prop if needed
_activeLink
is now_currentPage
_activeStep
is now_currentStep
- No more
focusBorderColor
anderrorBorderColor
, consider setting the--focus-color
and--error-color
css variables instead
- Remove
top-accent
andleft-accent
in favor addingborderLeft
andborderTop
directly to theAlert
component - Added new outline variant
- No more
soft-rounded
andsolid-rounded
variants - The
enclosed
variant has been modified - Added
plain
variant for usage withTabs.Indicator
- Changed
isManual
toactivationMode=manual
- Default color palette is now gray for all components but you can configure this in your theme.
- Move
hasStripe
andisAnimated
to thedecoration
variant in recipe. Value can be eitherstriped
orstriped-animated
- label or valueText no longer comes with a color by default, you can style yourself
No longer exists. Prefer to use the IconButton
component with your own icon.
- Remove
SkeletonText
andSkeletonCircle
in favor of using theSkeleton
component and styling as needed - Remove
fitContent
prop in favor of passingwidth="fit-content"
directly to theSkeleton
component - Remove
startColor
andendColor
prop in favor of using css variables
Skeleton Text
Before:
<SkeletonText />
After:
<Stack>
<Skeleton height="40px" />
<Skeleton height="40px" />
<Skeleton width="40%" height="40px" />
</Stack>
Skeleton Circle
Before:
<SkeletonCircle />
After:
<Skeleton width="40px" height="40px" rounded="full" />
- Renamed
Stepper
toSteps
- Changed data attribute format
data-status=complete
->data-complete
and style with_complete
data-status=active
->data-current
and style with_current
data-status=incomplete
->data-incomplete
and style with_incomplete
- Removed
StepIndicatorContent
, use theSteps.Status
component to render a component based on status
Before:
<Stepper index={activeStep}>
{steps.map((step, index) => (
<Step key={index}>
<StepIndicator>
<StepStatus
complete={<StepIcon />}
incomplete={<StepNumber />}
active={<StepNumber />}
/>
</StepIndicator>
<Box flexShrink="0">
<StepTitle>{step.title}</StepTitle>
<StepDescription>{step.description}</StepDescription>
</Box>
<StepSeparator />
</Step>
))}
</Stepper>
After:
<Steps.Root index={activeStep}>
{steps.map((step, index) => (
<Steps.Item key={index}>
<Steps.Indicator>
<Steps.Status
complete={<StepIcon />}
incomplete={<StepNumber />}
active={<StepNumber />}
/>
</Steps.Indicator>
<Box flexShrink="0">
<Steps.Title>{step.title}</Steps.Title>
<Steps.Description>{step.description}</Steps.Description>
</Box>
<Steps.Separator />
</Steps.Item>
))}
</Stepper>
- Rename to
Separator
- Switch to
div
element for better layout control - Simplify component to rely on
borderTopWidth
andborderInlineStartWidth
- To change the thickness reliably, set the
--divider-border-width
css variable
- Remove
shouldWrapChildren
in favor of using theStackItem
explicitly - Rename
spacing
togap
- Rename
divider
prop toseparator
- Rename
NumberInputStepper
toNumberInput.Control
- Rename
NumberInputStepperIncrement
toNumberInput.IncrementTrigger
- Rename
NumberInputStepperDecrement
toNumberInput.DecrementTrigger
- Remove
focusBorderColor
anderrorBorderColor
, consider setting the--focus-color
and--error-color
css variables instead
Before:
<NumberInput>
<NumberInputField />
<NumberInputStepper>
<NumberIncrementStepper />
<NumberDecrementStepper />
</NumberInputStepper>
</NumberInput>
After:
<NumberInput.Root>
<NumberInput.Field />
<NumberInput.Control>
<NumberInput.IncrementTrigger />
<NumberInput.DecrementTrigger />
</NumberInput.Control>
</NumberInput.Root>
- Changed
value
,defaultValue
andonChange
to usestring[]
instead ofstring
- Add new
PinInput.Control
andPinInput.Label
component parts PinInput.Root
now renders adiv
element by default. Consider combining withStack
orGroup
for better layout control
- Now renders a native
img
without any fallback - Remove
fallbackSrc
due to the SSR issues it causes - Remove
useImage
hook - Remove
Img
in favor of using theImage
component directly
There's been a significant change to the Toast
component to make it more
flexible and easier to style.
- Removed
createStandaloneToasts
,useToast
in favor of usingcreateToaster
to spawn toast in a specific position. - With the
toast
returned fromcreateToaster
, you can now create toasts outside of the React tree. - Toast now reads from its own recipe and all parts can be styled directly
Before:
import { useToast } from "@chakra-ui/react"
const toast = useToast()
toast({
title: "Account created.",
description: "We've created your account for you.",
status: "success",
})
After:
const [ToastContainer, toast] = createToaster({
placement: "bottom",
render(toast) {
return (
<Toast.Transition>
<Toast.Root status={toast.status}>
<Toast.Title>{toast.title}</Toast.Title>
<Toast.Description>{toast.description}</Toast.Description>
<Box pos="absolute" top="1" insetEnd="1">
<Toast.CloseTrigger asChild>
<HiX />
</Toast.CloseTrigger>
</Box>
</Toast.Root>
</Toast.Transition>
)
},
})
toast({
title: "Account created.",
description: "We've created your account for you.",
status: "success",
})
- Remove
appendToParentPortal
prop in favor of using thecontainerRef
- Simplify the
Portal
component - Remove
PortalManager
component
- We've removed the
ColorModeProvider
anduseColorMode
in favor of usingnext-themes
or similar libraries. - Removed
LightMode
,DarkMode
andColorModeScript
components - Removed
useColorModeValue
in favor of usinguseTheme
fromnext-themes
// TODO: Provide snippets
_activeLink
->_currentPage
_activeStep
->_currentStep
apply
is no longer supported, prefer creating a recipe using thechakra
factory instead
- Rename
StatArrow
toStat.Indicator
- Rename
StatNumber
toStat.Value
- Now requires the
Slider.Control
to work properly - Added new
Slider.ValueText
andSlider.Label
components