Tag Group

A wrapping set of selectable tags for filters and multi-choice chip sets.

Tag Group is a wrapping row of tags the user can select, one at a time or several at once. It is built for filters, such as the category pills above the base.org ecosystem grid, and for chip sets where any number of options can be on. Put the tags in a TagList; the group carries the size, selection and label, and every tag restyles itself from it.

import { TagGroup, TagList, Tag } from '@base-org/bds-web/product/tag-group';

<TagGroup aria-label="Category" selectionMode="multiple">
  <TagList>
    <Tag id="defi">DeFi</Tag>
    <Tag id="ai">AI</Tag>
  </TagList>
</TagGroup>;

Sizes

Medium

The default. A 36px pill with a full radius, 16px of side padding, a hairline border and 14px text. An unselected tag is transparent and fills light gray on hover; a selected tag fills gray, a step darker on hover. Use it for filters on wider screens.

All
DeFi
AI
Boost Campaigns
<TagGroup aria-label="Category" selectionMode="single" defaultSelectedKeys={['all']}>
<TagList>
  <Tag id="all">All</Tag>
  <Tag id="defi">DeFi</Tag>
  <Tag id="ai">AI</Tag>
  <Tag id="boost">Boost Campaigns</Tag>
</TagList>
</TagGroup>

Small

size="sm" is a 32px chip with an 8px radius and 8px of side padding. An unselected chip has muted text and border and darkens on hover; a selected chip takes the inverse fill. Use it in compact layouts and mobile filter sheets.

DEX
Lending
Payments
<TagGroup size="sm" aria-label="Subcategory" selectionMode="multiple" defaultSelectedKeys={['dex']}>
<TagList>
  <Tag id="dex">DEX</Tag>
  <Tag id="lending">Lending</Tag>
  <Tag id="payments">Payments</Tag>
</TagList>
</TagGroup>

Selection

Single

selectionMode="single" keeps at most one tag selected; choosing another moves the selection. Use defaultSelectedKeys for uncontrolled use, or selectedKeys with onSelectionChange when the parent owns the filter. Add disallowEmptySelection when one tag must always stay on, such as an All tag.

All
DeFi
NFT
<TagGroup
aria-label="Category"
selectionMode="single"
disallowEmptySelection
defaultSelectedKeys={['all']}
>
<TagList>
  <Tag id="all">All</Tag>
  <Tag id="defi">DeFi</Tag>
  <Tag id="nft">NFT</Tag>
</TagList>
</TagGroup>

Multiple

selectionMode="multiple" lets any number of tags be on at once. Give every Tag Group a selectionMode or onRemove; tags that only display a label belong in a Badge, not a Tag Group.

Base
Ethereum
Optimism
<TagGroup aria-label="Networks" selectionMode="multiple" defaultSelectedKeys={['base', 'ethereum']}>
<TagList>
  <Tag id="base">Base</Tag>
  <Tag id="ethereum">Ethereum</Tag>
  <Tag id="optimism">Optimism</Tag>
</TagList>
</TagGroup>

Label and removal

With label

label puts a visible label above the tags and names the group. Without one, pass aria-label.

Category
DeFi
AI
<TagGroup label="Category" selectionMode="multiple">
<TagList>
  <Tag id="defi">DeFi</Tag>
  <Tag id="ai">AI</Tag>
</TagList>
</TagGroup>

Removable

Pass onRemove and every tag gets a remove button after its text. The handler receives the keys to remove; the group does not remove anything itself, so drop the keys from your own list. Backspace and Delete remove the focused tag too.

DeFi
AI
Gaming
const [tags, setTags] = useState(['DeFi', 'AI', 'Gaming']);

<TagGroup
aria-label="Active filters"
onRemove={(keys) => setTags(tags.filter((tag) => !keys.has(tag)))}
>
<TagList>
  {tags.map((tag) => (
    <Tag key={tag} id={tag}>{tag}</Tag>
  ))}
</TagList>
</TagGroup>

When to use

Use Tag Group for filters and chip sets where the user turns options on and off, especially when several can be on at once or the options wrap onto more than one line.

Use something else when:

  • The choice is one of two to five short options, a compact mode switch that always has a value. Use Segment.
  • The tags only display labels and the user never selects or removes them. Use a Badge with variant="tag". Badge shows tags; Tag Group lets the user choose them.
  • The list is long or changes at runtime and belongs in a dropdown. Use Select with selectionMode="multiple".
  • The options switch whole panels of content. Use Tabs.

Usage

Do

Keep tag text to one or two words, and use one size per group: md for page filters, sm for compact sheets and chip sets.

Don't

Use a Tag Group for actions. Tags change a selection; a tag that runs a command is a Button.

Props

TagGroup

PropTypeDefault
children

The children of the component.

TypeReactNodeDefault—
className

The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the

TypestringDefault—
defaultSelectedKeys

The initial selected keys in the collection (uncontrolled).

TypeIterable<Key> | "all"Default—
disabledKeys

The item keys that are disabled. These items cannot be selected, focused, or otherwise

TypeIterable<Key>Default—
disallowEmptySelection

Whether the collection allows empty selection.

TypebooleanDefault—
escapeKeyBehavior

Whether pressing the escape key should clear selection in the TagGroup or not.

Type"clearSelection" | "none"Default'clearSelection'
label

A visible label above the tags. Without one, pass `aria-label`.

TypeReactNodeDefault—
selectedKeys

The currently selected keys in the collection (controlled).

TypeIterable<Key> | "all"Default—
selectionBehavior

How multiple selection should behave in the collection.

Type"toggle" | "replace"Default'toggle'
selectionMode

The type of selection that is allowed in the collection.

Type"none" | "single" | "multiple"Default—
shouldSelectOnPressUp

Whether selection should occur on press up instead of press down.

TypebooleanDefault—
size

`md` is the 36px rounded pill for desktop filters. `sm` is the 32px chip

Type"sm" | "md"Defaultmd

TagList

PropTypeDefault
children

The contents of the collection.

TypeReactNode | ((item: T) => ReactNode)Default—
className

The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the

TypestringDefault—
dependencies

Values that should invalidate the item cache when using dynamic collections.

Typereadonly any[]Default—
items

Item objects in the collection.

TypeIterable<T>Default—
renderEmptyState

Provides content to display when there are no items in the tag list.

Type((props: TagListRenderProps) => ReactNode)Default—

Tag

PropTypeDefault
children

The children of the component. A function may be provided to alter the children based on

TypeChildrenOrFunction<TagRenderProps>Default—
className

The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the

TypestringDefault—
href

A URL to link to. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#href).

TypestringDefault—
isDisabled

Whether the tag is disabled.

TypebooleanDefault—
rel

The relationship between the linked resource and the current page. See

TypestringDefault—
target

The target window for the link. See

TypeHTMLAttributeAnchorTargetDefault—
textValue

A string representation of the tags's contents, used for accessibility.

TypestringDefault—

TagGroupLabel

PropTypeDefault
elementTypeTypestringDefault—

TagRemoveButton

PropTypeDefault
children

The children of the component. A function may be provided to alter the children based on

TypeChildrenOrFunction<TagRenderProps>Default—
className

The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the

TypeClassNameOrFunction<ButtonRenderProps>Default—
isDisabled

Whether the button is disabled.

TypebooleanDefault—
isPending

Whether the button is in a pending state. This disables press and hover events

TypebooleanDefault—
type

The behavior of the button when used in an HTML form.

Type"button" | "submit" | "reset"Default'button'

Accessibility

Tag Group wraps React Aria's TagGroup, TagList and Tag. The list is a grid and each tag a row, so the group is one tab stop and the arrow keys move between tags. Space or Enter toggles the focused tag, and each selected tag is announced as selected. Name the group with label or aria-label.

With onRemove, Backspace and Delete remove the focused tag. The remove button is named "Remove" by React Aria and sits out of the tab order, so keyboard users remove with those keys instead; its icon is hidden from screen readers.

Colour transitions are instant when the reader prefers reduced motion.