Skip to main content

Tags

One row of tags that keeps to its width, collapsing the rest into an overflow tag. It is what a room row and a room card use to show their tags on a single line.

TagsTags

Use this when / not when​

  • Use for the tags of one object, on one line, where the row's width is fixed and the extras have to go somewhere.
  • Not for a single tag — Tag on its own is smaller and lets you set its width yourself.
  • Not for a wrapping cloud of tags; this row is overflow: hidden and never wraps. Lay Tags out in your own flex container for that.
  • Not for the user's own picks, which should be removable — that is SelectedItem.

Import​

import { Tags } from "@onlyoffice/apps-ui-kit/components/tags";

Also exported from the root barrel @onlyoffice/apps-ui-kit.

Needs ThemeProvider from @onlyoffice/apps-ui-kit/providers/theme, which the tags and the overflow menu both read their colours from.

Stories​

Default​

DefaultDefault

Multiple Tags​

Five tags side by side, each given an equal share of the row, for when the column count leaves room for all of them.

Multiple TagsMultiple Tags

With Overflow​

Three tags and a ... tag; click it to list the other three in a drop-down, and click an entry to select it (onSelectTag). Switch removeTagIcon in the Controls panel below to see the entries lose their leading margin.

With OverflowWith Overflow

With Tag Objects​

Design carries an icon before its label, Review a suffix after it, and the third tag is only its icon at a fixed width (isThirdParty) — the looks a plain string cannot ask for.

With Tag ObjectsWith Tag Objects

Show All​

All five tags at their natural width with no overflow tag, for a place where every tag must stay visible (columnCount={-1}); tags that do not fit are cut off at the container edge.

Show AllShow All

With Create Tag​

A plus tag after the two tags, for offering to add one more (showCreateTag); clicking it calls onOptionTagClick, and it disappears once the tags overflow.

With Create TagWith Create Tag

With Custom Option Tag​

Two tags and a +1 count instead of ..., for when the hidden tags belong in a menu of your own: clicking the count opens no drop-down and calls onOptionTagClick, and optionTagRef points at it for anchoring.

With Custom Option TagWith Custom Option Tag

Css Customization​

The variable is listed under CSS variables on this page. The example sets it to 24px on the document; click the ... tag to see the entry Invoice start further from the menu's edge.

Css CustomizationCss Customization

Minimal example​

columnCount is how many tags are drawn before the rest collapse; it is required.

import { Tags } from "@onlyoffice/apps-ui-kit/components/tags";

export function RoomTags({ tags }: { tags: string[] }) {
return (
<div style={{ width: 320 }}>
<Tags
tags={tags}
columnCount={3}
onSelectTag={(tag) => console.log(tag.label)}
/>
</div>
);
}

Props​

PropertyTypeDescription
columnCountnumberHow many tags are drawn before the rest collapse into one overflow tag. -1 draws all of them.
onSelectTag(tag: TagClickEvent) => voidCalled with { label, roomType, providerType } when a tag, or an entry of the overflow drop-down, is clicked.
tags(string | TagType)[]Tags to lay out. A bare string is treated as { label }.
className?stringApplied to the outermost element.
id?stringApplied to the outermost element.
onMouseEnter?VoidFunctionCalled when the pointer enters any tag. It is not told which one.
onMouseLeave?VoidFunctionCalled when the pointer leaves any tag.
onOptionTagClick?VoidFunctionCalled when the overflow tag or the create tag is clicked. Passing it replaces the built-in drop-down.
optionTagRef?RefObject<HTMLDivElement | null>Ref to the overflow tag, for a menu of your own anchored to it.
removeTagIcon?booleanPassed to the overflow drop-down, where it removes the leading margin of each entry. Default: false.
showCreateTag?booleanWhether a plus tag is drawn for creating a new one. It is dropped as soon as the tags overflow.
style?CSSPropertiesApplied to the outermost element as inline style.

Each entry is a string or a TagType, whose fields are listed in Tag.

Recipes​

All tags, no collapsing​

columnCount={-1} draws every tag at a 195px cap and never builds an overflow tag. The row still does not wrap, so anything past its width is clipped.

import { Tags } from "@onlyoffice/apps-ui-kit/components/tags";

export function AllRoomTags({ tags }: { tags: string[] }) {
return (
<Tags
tags={tags}
columnCount={-1}
onSelectTag={(tag) => alert(tag.label)}
/>
);
}

Your own overflow menu​

Passing onOptionTagClick replaces the built-in drop-down: the overflow tag is then labelled +N and clicking it calls you, with optionTagRef pointing at the element to anchor to.

import { useRef, useState } from "react";
import { Tags } from "@onlyoffice/apps-ui-kit/components/tags";
import { DropDown } from "@onlyoffice/apps-ui-kit/components/drop-down";
import { DropDownItem } from "@onlyoffice/apps-ui-kit/components/drop-down-item";

export function RoomTagsWithMenu({ tags }: { tags: string[] }) {
const anchor = useRef<HTMLDivElement | null>(null);
const [open, setOpen] = useState(false);

return (
<div style={{ width: 280 }}>
<Tags
tags={tags}
columnCount={2}
optionTagRef={anchor}
onOptionTagClick={() => setOpen(true)}
onSelectTag={(tag) => console.log(tag.label)}
/>
<DropDown
open={open}
forwardedRef={anchor}
clickOutsideAction={() => setOpen(false)}
>
{tags.slice(2).map((tag) => (
<DropDownItem key={tag} label={tag} onClick={() => setOpen(false)} />
))}
</DropDown>
</div>
);
}

Behaviour the types don't state​

  • The row's width is shared out among the visible tags. Each gets an equal percentage maxWidth of the measured width, less room for the overflow or create tag, so a long label truncates with an ellipsis instead of widening the row.
  • The widths are measured once per change of tags, columnCount or showCreateTag. There is no ResizeObserver: resizing the container, or the row growing because a sibling shrank, leaves every tag at the percentage computed for the old width.
  • columnCount is a count of tags, not of pixels. -1 means "draw them all", 0 means "collapse them all into the overflow tag", and anything smaller than tags.length produces the overflow tag as an extra element after that many tags.
  • The overflow tag looks different depending on whether you handle it. Without onOptionTagClick it is labelled ... and opens a DropDown of the hidden labels; with it, the label becomes +N and the menu is yours to render.
  • showCreateTag is dropped as soon as the tags overflow. The plus tag is only appended on the branch where everything fits, so a row that needs an overflow tag silently loses its "add" affordance.
  • The create tag and the overflow tag share onOptionTagClick and optionTagRef, so one handler is called for both and cannot tell them apart.
  • onSelectTag is the only way a tag reports a click. TagType.onClick is ignored: every tag is wired to onSelectTag, and an entry of the built-in menu reports through it too.
  • Tags are keyed by their label. Two tags with the same text collide on the React key, and the data-testid of both becomes tag_item_<label>.
  • A TagType marked isThirdParty is fixed at 44px and its label is not rendered — only its icon is, so such a tag must carry one.
  • maxWidth on a TagType is overwritten, always, by the width the row computes.
  • The row is display: flex, width: 100% and overflow: hidden. It takes the width of its parent and clips, so the parent is what decides how much fits.
  • removeTagIcon does not remove anything: it drops the leading margin of each entry in the built-in overflow menu.
  • TagsProps is not exported from the folder's entry point — type a wrapper's props with React.ComponentProps<typeof Tags>.

CSS variables​

The row itself has one; the tags inside follow Tag.

VariableDefaultEffect
--tags-overflow-text-margin8pxLeading margin of an entry in the overflow menu.

The overflow menu is portalled to the document body, so this variable reaches it only when it is set on :root or body; a wrapper, or the style prop, never does. It is ignored under removeTagIcon, which drops the margin altogether.

Accessibility​

  • The row is a <div> with the hardcoded English aria-label="Tags container", which cannot be overridden and does not change with the interface language. The <div> has no role, so most screen readers do not announce the label at all.
  • Everything else comes from each Tag: its label is its accessible name (aria-label), and a disabled tag carries aria-disabled.
  • It has no list semantics: the tags are not <li>s and the row is not a <ul>, so a screen reader reads a run of labels with no sense of how many there are.
  • No tag can be reached from the keyboard — see Tag — and neither can the overflow tag, so the hidden labels are unreachable without a mouse.
  • The overflow menu is a DropDown and inherits its behaviour, including closing on an outside click.

Test ids​

Elementdata-testid
The rowtags
A tagtag_item_<label>
The overflow tagtag_item
An entry of its menutag_dropdown_item

None of them can be overridden by a prop.

  • Tag — one tag, and the shape of an entry.
  • DropDown — the overflow menu.
  • SelectedItem — the removable chip for a user's own choice.