Build faster with Premium Chakra UI Components 💎
Learn moreOctober 20, 2025
SASegun Adebayo
@thesegunadebayo
TATolulope Adebesin
@I_am_Lope
We've just shipped Chakra UI v3.28! This release introduces the highly requested TagsInput component, bringing powerful multi-value input capabilities to Chakra UI.
This release also includes comprehensive bug fixes and improvements across 14+ components, addressing edge cases in form handling, accessibility, and cross-browser compatibility.
The TagsInput component provides a robust interface for entering and managing multiple values as tags. Think of it as a multi-value input with built-in keyboard navigation, tag editing, validation, and deletion—all the complexity handled for you.
Use it for skill selection, email recipients, keyword tagging, category assignment, or any scenario where users need to input multiple discrete values.
"use client"
import { Span, TagsInput } from "@chakra-ui/react"
const Demo = () => {
return (
<TagsInput.Root defaultValue={["React", "Chakra", "TypeScript"]}>
<TagsInput.Label>Tags</TagsInput.Label>
<TagsInput.Control>
<TagsInput.Items />
<TagsInput.Input placeholder="Add tag..." />
</TagsInput.Control>
<Span textStyle="xs" color="fg.muted" ms="auto">
Press Enter or Return to add tag
</Span>
</TagsInput.Root>
)
}
TagsInput works seamlessly with Combobox to create an autocomplete tag input—perfect for suggesting existing tags or categories as users type.
"use client"
import {
Combobox,
TagsInput,
useCombobox,
useFilter,
useListCollection,
useTagsInput,
} from "@chakra-ui/react"
import { useId, useRef } from "react"
const Demo = () => {
const { contains } = useFilter({ sensitivity: "base" })
const { collection, filter } = useListCollection({
initialItems: [
"React",
"Chakra",
"TypeScript",
"Next.js",
"Ark UI",
"Zag.js",
],
filter: contains,
})
const inputId = useId()
const controlRef = useRef<HTMLDivElement | null>(null)
const tags = useTagsInput({
ids: { input: inputId },
})
const comobobox = useCombobox({
ids: { input: inputId },
collection,
onInputValueChange(e) {
filter(e.inputValue)
},
positioning: {
getAnchorRect() {
return controlRef.current!.getBoundingClientRect()
},
},
value: [],
allowCustomValue: true,
onValueChange: (e) => tags.addValue(e.value[0]),
selectionBehavior: "clear",
})
return (
<Combobox.RootProvider value={comobobox}>
<TagsInput.RootProvider value={tags}>
<TagsInput.Label>Tags</TagsInput.Label>
<TagsInput.Control ref={controlRef}>
{tags.value.map((tag, index) => (
<TagsInput.Item key={index} index={index} value={tag}>
<TagsInput.ItemPreview>
<TagsInput.ItemText>{tag}</TagsInput.ItemText>
<TagsInput.ItemDeleteTrigger />
</TagsInput.ItemPreview>
</TagsInput.Item>
))}
<Combobox.Input unstyled asChild>
<TagsInput.Input placeholder="Add tag..." />
</Combobox.Input>
</TagsInput.Control>
<Combobox.Positioner>
<Combobox.Content>
<Combobox.Empty>No tags found</Combobox.Empty>
{collection.items.map((item) => (
<Combobox.Item item={item} key={item}>
<Combobox.ItemText>{item}</Combobox.ItemText>
<Combobox.ItemIndicator />
</Combobox.Item>
))}
</Combobox.Content>
</Combobox.Positioner>
</TagsInput.RootProvider>
</Combobox.RootProvider>
)
}
The Collapsible component now supports collapsedHeight and collapsedWidth
props, allowing you to show a preview of the content when collapsed instead of
hiding it completely.
This is particularly useful for "Read more" patterns, content previews, or showing the first few lines of a long text block before expanding.
Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.
Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.
"use client"
import { Button, Collapsible, Stack } from "@chakra-ui/react"
import { LuChevronDown } from "react-icons/lu"
import { LoremIpsum } from "react-lorem-ipsum"
const Demo = () => (
<Collapsible.Root collapsedHeight="100px">
<Collapsible.Content
_closed={{
shadow: "inset 0 -12px 12px -12px var(--shadow-color)",
shadowColor: "blackAlpha.500",
}}
>
<Stack padding="4" borderWidth="1px" rounded="l2">
<LoremIpsum p={1} />
<LoremIpsum p={1} />
</Stack>
</Collapsible.Content>
<Collapsible.Trigger asChild mt="4">
<Button variant="outline" size="sm">
<Collapsible.Context>
{(api) => (api.open ? "Show Less" : "Show More")}
</Collapsible.Context>
<Collapsible.Indicator
transition="transform 0.2s"
_open={{ transform: "rotate(180deg)" }}
>
<LuChevronDown />
</Collapsible.Indicator>
</Button>
</Collapsible.Trigger>
</Collapsible.Root>
)
This release includes comprehensive bug fixes across 14+ components:
indeterminate initial state and api.checkedState
accuracyaria-controlsgetPageUrl prop for link-based paginationCmd+Backspace and Cmd+Delete keyboard shortcutsrequired state accessibilitydata-active attribute consistency with runtime disabled
changesgetBoundingClientRect()To upgrade to the latest version, run:
npm install @chakra-ui/react@latestAll improvements in this release are backward compatible—no breaking changes or migration required.
We're excited to see what you build with TagsInput! Share your creations with us on Twitter or join the conversation in our Discord community.