TagGroupNew

A compound component for displaying and managing selectable tags with optional removal.

Import

import { TagGroup } from 'heroui-native';

Anatomy

<TagGroup>
  <TagGroup.List>
    <TagGroup.Item id="tag-1">
      <TagGroup.ItemLabel>...</TagGroup.ItemLabel>
      <TagGroup.ItemRemoveButton />
    </TagGroup.Item>
  </TagGroup.List>
</TagGroup>
  • TagGroup: Main container that manages tag selection state, disabled keys, and remove functionality. Provides size and variant context to all child components.
  • TagGroup.List: Container for rendering the list of tags with optional empty state rendering.
  • TagGroup.Item: Individual tag within the group. Supports string children (auto-wrapped in TagGroup.ItemLabel), render function children, or custom layouts.
  • TagGroup.ItemLabel: Text label for the tag. Automatically rendered when string children are provided, or can be used explicitly.
  • TagGroup.ItemRemoveButton: Remove button for the tag. Must be placed explicitly when removal is needed. Only functional when onRemove is provided to TagGroup.

Usage

Basic Usage

Display a simple tag group with selectable items.

<TagGroup selectionMode="single">
  <TagGroup.List>
    <TagGroup.Item id="news">News</TagGroup.Item>
    <TagGroup.Item id="travel">Travel</TagGroup.Item>
    <TagGroup.Item id="gaming">Gaming</TagGroup.Item>
  </TagGroup.List>
</TagGroup>

Single Selection Mode

Allow only one tag to be selected at a time.

<TagGroup selectionMode="single" defaultSelectedKeys={['news']}>
  <TagGroup.List>
    <TagGroup.Item id="news">News</TagGroup.Item>
    <TagGroup.Item id="travel">Travel</TagGroup.Item>
    <TagGroup.Item id="gaming">Gaming</TagGroup.Item>
  </TagGroup.List>
</TagGroup>

Multiple Selection Mode

Allow multiple tags to be selected simultaneously.

<TagGroup selectionMode="multiple" defaultSelectedKeys={['news', 'travel']}>
  <TagGroup.List>
    <TagGroup.Item id="news">News</TagGroup.Item>
    <TagGroup.Item id="travel">Travel</TagGroup.Item>
    <TagGroup.Item id="gaming">Gaming</TagGroup.Item>
  </TagGroup.List>
</TagGroup>

Controlled Selection

Control selection state with selectedKeys and onSelectionChange.

const [selected, setSelected] = useState(new Set(['news']));

<TagGroup
  selectionMode="single"
  selectedKeys={selected}
  onSelectionChange={setSelected}
>
  <TagGroup.List>
    <TagGroup.Item id="news">News</TagGroup.Item>
    <TagGroup.Item id="travel">Travel</TagGroup.Item>
    <TagGroup.Item id="gaming">Gaming</TagGroup.Item>
  </TagGroup.List>
</TagGroup>;

Variants

Apply different visual variants to the tags.

<TagGroup selectionMode="single" variant="default">
  <TagGroup.List>
    <TagGroup.Item id="news">News</TagGroup.Item>
    <TagGroup.Item id="travel">Travel</TagGroup.Item>
  </TagGroup.List>
</TagGroup>

<TagGroup selectionMode="single" variant="surface">
  <TagGroup.List>
    <TagGroup.Item id="news">News</TagGroup.Item>
    <TagGroup.Item id="travel">Travel</TagGroup.Item>
  </TagGroup.List>
</TagGroup>

Sizes

Control the size of all tags in the group.

<TagGroup selectionMode="single" size="sm">
  <TagGroup.List>
    <TagGroup.Item id="news">News</TagGroup.Item>
  </TagGroup.List>
</TagGroup>

<TagGroup selectionMode="single" size="md">
  <TagGroup.List>
    <TagGroup.Item id="news">News</TagGroup.Item>
  </TagGroup.List>
</TagGroup>

<TagGroup selectionMode="single" size="lg">
  <TagGroup.List>
    <TagGroup.Item id="news">News</TagGroup.Item>
  </TagGroup.List>
</TagGroup>

With Remove Button

Add remove buttons to tags by providing onRemove and placing TagGroup.ItemRemoveButton in each item.

const [tags, setTags] = useState([
  { id: 'news', name: 'News' },
  { id: 'travel', name: 'Travel' },
]);

const onRemove = (keys) => {
  setTags((prev) => prev.filter((tag) => !keys.has(tag.id)));
};

<TagGroup selectionMode="single" onRemove={onRemove}>
  <TagGroup.List>
    {tags.map((tag) => (
      <TagGroup.Item key={tag.id} id={tag.id}>
        <TagGroup.ItemLabel>{tag.name}</TagGroup.ItemLabel>
        <TagGroup.ItemRemoveButton />
      </TagGroup.Item>
    ))}
  </TagGroup.List>
</TagGroup>;

Render Function Children

Use a render function to access isSelected and isDisabled for custom layouts.

<TagGroup selectionMode="single">
  <TagGroup.List>
    <TagGroup.Item id="news">
      {({ isSelected }) => (
        <>
          <SquareArticleIcon
            size={16}
            colorClassName={
              isSelected
                ? 'accent-accent-soft-foreground'
                : 'accent-field-foreground'
            }
          />
          <TagGroup.ItemLabel>News</TagGroup.ItemLabel>
        </>
      )}
    </TagGroup.Item>
  </TagGroup.List>
</TagGroup>

Empty State

Render custom content when the list has no tags.

<TagGroup onRemove={onRemove}>
  <TagGroup.List
    renderEmptyState={() => (
      <Text className="text-sm text-muted">No categories found</Text>
    )}
  >
    {tags.map((tag) => (
      <TagGroup.Item key={tag.id} id={tag.id}>
        <TagGroup.ItemLabel>{tag.name}</TagGroup.ItemLabel>
        <TagGroup.ItemRemoveButton />
      </TagGroup.Item>
    ))}
  </TagGroup.List>
</TagGroup>

Disabled Tags

Disable individual tags or the entire group.

<TagGroup selectionMode="single" disabledKeys={new Set(['travel'])}>
  <TagGroup.List>
    <TagGroup.Item id="news">News</TagGroup.Item>
    <TagGroup.Item id="travel">Travel</TagGroup.Item>
    <TagGroup.Item id="gaming" isDisabled>
      Gaming
    </TagGroup.Item>
  </TagGroup.List>
</TagGroup>

Example

import { TagGroup, Label, Description, FieldError } from 'heroui-native';
import { useState, useMemo } from 'react';
import { View } from 'react-native';

export default function TagGroupExample() {
  const [selected, setSelected] = useState(new Set());
  const isInvalid = useMemo(
    () => Array.from(selected).length === 0,
    [selected]
  );

  return (
    <View className="gap-4">
      <TagGroup
        selectedKeys={selected}
        selectionMode="multiple"
        onSelectionChange={setSelected}
        isInvalid={isInvalid}
      >
        <Label isInvalid={false}>Amenities</Label>
        <TagGroup.List>
          <TagGroup.Item id="laundry">Laundry</TagGroup.Item>
          <TagGroup.Item id="fitness">Fitness center</TagGroup.Item>
          <TagGroup.Item id="parking">Parking</TagGroup.Item>
          <TagGroup.Item id="pool">Swimming pool</TagGroup.Item>
          <TagGroup.Item id="breakfast">Breakfast</TagGroup.Item>
        </TagGroup.List>
        <Description hideOnInvalid>
          {`Selected: ${Array.from(selected).join(', ')}`}
        </Description>
        <FieldError>Please select at least one category</FieldError>
      </TagGroup>
    </View>
  );
}

You can find more examples in the GitHub repository.

API Reference

TagGroup

proptypedefaultdescription
childrenReact.ReactNode-Child elements to render inside the tag group
size'sm' | 'md' | 'lg''md'Size of all tags in the group
variant'default' | 'surface''default'Visual variant of all tags in the group
selectionMode'none' | 'single' | 'multiple''none'The type of selection allowed in the tag group
selectedKeysIterable<TagKey>-The currently selected keys (controlled)
defaultSelectedKeysIterable<TagKey>-The initial selected keys (uncontrolled)
disabledKeysIterable<TagKey>-Keys of tags that should be disabled
isDisabledbooleanfalseWhether the entire tag group is disabled
isInvalidbooleanfalseWhether the tag group is in an invalid state
isRequiredbooleanfalseWhether the tag group is required
classNamestring-Additional CSS classes for the tag group container
styleStyleProp<ViewStyle>-Additional styles for the tag group container
animation"disable-all" | undefined-Use "disable-all" to disable all animations including children
onSelectionChange(keys: Set<TagKey>) => void-Handler called when the selection changes
onRemove(keys: Set<TagKey>) => void-Handler called when tags are removed
...ViewPropsViewProps-All standard React Native View props are supported

TagKey

string | number — Key type for identifying tags within a TagGroup.

Animation

Use animation="disable-all" to disable all animations including children. Omit or use undefined for default animations.

TagGroup.List

proptypedefaultdescription
childrenReact.ReactNode-Child elements to render inside the list
classNamestring-Additional CSS classes for the list container
styleStyleProp<ViewStyle>-Additional styles for the list container
renderEmptyState() => React.ReactNode-Function to render when the list has no tags
...ViewPropsViewProps-All standard React Native View props are supported

TagGroup.Item

proptypedefaultdescription
childrenReact.ReactNode | ((renderProps: TagRenderProps) => React.ReactNode)-Tag content: string, elements, or a render function receiving TagRenderProps
idTagKey-Unique identifier for this tag
isDisabledboolean-Whether this specific tag is disabled
classNamestring-Additional CSS classes for the tag
styleStyleProp<ViewStyle>-Additional styles for the tag
...PressablePropsPressableProps-All standard React Native Pressable props are supported

TagRenderProps

proptypedescription
isSelectedbooleanWhether the tag is currently selected
isDisabledbooleanWhether the tag is disabled (merged from root, disabledKeys, and item prop)

TagGroup.ItemLabel

proptypedefaultdescription
childrenReact.ReactNode-Text content to render
classNamestring-Additional CSS classes for the label
...TextPropsTextProps-All standard React Native Text props are supported

TagGroup.ItemRemoveButton

proptypedefaultdescription
childrenReact.ReactNode-Custom icon or content for the remove button. Defaults to close icon when omitted
classNamestring-Additional CSS classes for the remove button
iconPropsTagRemoveButtonIconProps-Props for customizing the default close icon. Only applies when no children are provided
hitSlopnumber8Extends the touchable area
...PressablePropsPressableProps-All standard React Native Pressable props are supported

TagRemoveButtonIconProps

proptypedefaultdescription
sizenumber12Size of the icon
colorstring-Color of the icon

Hooks

useTagGroup

Hook to access the tag group root context. Must be used within a TagGroup component.

import { useTagGroup } from 'heroui-native';

const {
  selectedKeys,
  disabledKeys,
  selectionMode,
  onSelectionChange,
  onRemove,
  isDisabled,
  isInvalid,
  isRequired,
} = useTagGroup();

Returns

propertytypedescription
selectionMode'none' | 'single' | 'multiple'The type of selection allowed in the tag group
selectedKeysSet<TagKey>Currently selected tag keys
disabledKeysSet<TagKey>Keys of disabled tags
onSelectionChange(keys: Set<TagKey>) => voidCallback when selection changes
onRemove((keys: Set<TagKey>) => void) | undefinedCallback when tags are removed
isDisabledbooleanWhether the entire tag group is disabled
isInvalidbooleanWhether the tag group is in an invalid state
isRequiredbooleanWhether the tag group is required

useTagGroupItem

Hook to access the tag item context. Must be used within a TagGroup.Item component.

import { useTagGroupItem } from 'heroui-native';

const { id, isSelected, isDisabled, allowsRemoving } = useTagGroupItem();

Returns

propertytypedescription
idTagKeyUnique identifier for this tag
isSelectedbooleanWhether the tag is currently selected
isDisabledbooleanWhether the tag is disabled
allowsRemovingbooleanWhether the tag can be removed (true when onRemove is provided to TagGroup)

On this page