Tag
Small outlined label for one keyword, clickable and optionally removable. It is the room tag
of the portal, and the piece Tags lays out in a row.
Use this when / not when
- Use for a keyword attached to an object — a room tag, a category, a provider — that the reader may click to filter by.
- Not for several tags side by side:
Tagsmeasures the row, collapses the overflow into a menu and passes each tag the width it may take. - Not for something the user chose and can undo —
SelectedItemis the chip with a cross for that. - Not for a count or a status word;
Badgeis the filled pill.
Import
import { Tag } from "@onlyoffice/apps-ui-kit/components/tag";
Also exported from the root barrel @onlyoffice/apps-ui-kit.
Needs ThemeProvider from @onlyoffice/apps-ui-kit/providers/theme; without it the tag has no
border and no colours.
Stories
Default
A plain tag with a label, the starting point for every other state; change any prop live in the Controls panel below.
States
The four looks a tag can take, side by side, to pick the one that matches an item's status:
- Default — a bordered tag on the plain background
- New Tag — a filled tag with a delete cross after the label (
isNewTagwithonDelete) - Disabled — a dashed border; the tag ignores hover and clicks (
isDisabled) - Deleted — a greyed-out border; clicks no longer reach
onClick(isDeleted)
New Tags
Tags the user has just added and can still take back: click a cross to remove its tag, and the Actions panel shows the identifier onDelete receives.
Clickable Tags
Tags that act as filters: hover one to see it highlight, click it, and the Actions panel shows the { label } object onClick receives instead of the DOM event.
Max Width Variants
Tags with different max-width values. Long text is truncated with ellipsis when it exceeds the max width.
Icon Only
A compact tag that is only a glyph marks where an item comes from without taking the width of a label; the hidden label still names the tag for screen readers (withLabel={false}):
- First tag — the glyph loaded from an SVG file (
iconas a URL) - Second tag — the same glyph passed as a React component (
iconas a component)
With Label Suffix
A count after the label, in a quieter colour, tells the reader how many items the tag covers without a second element (labelSuffix, labelSuffixColor).
Css Customization
Six variables set on one wrapper -- the variables are listed under CSS variables on this page. Both tags take every variable from the wrapper; the second is there to show the space --tag-spacing-end leaves after Custom Tag.
Minimal example
onClick is handed an object, not the DOM event.
import { Tag } from "@onlyoffice/apps-ui-kit/components/tag";
export function RoomTag({ onFilter }: { onFilter: (label: string) => void }) {
return (
<Tag tag="finance" label="Finance" onClick={(e) => onFilter(e.label)} />
);
}
Props
Tags accepts a different, wider shape for each entry of its row:
Recipes
Disabled / read-only
isDisabled dashes the border and drops pointer events in CSS, so hover does nothing either.
import { Tag } from "@onlyoffice/apps-ui-kit/components/tag";
export function ArchivedTag() {
return <Tag tag="archive" label="Archived" isDisabled />;
}
Removable
The cross needs both isNewTag and onDelete; either alone renders no cross.
import { useState } from "react";
import { Tag } from "@onlyoffice/apps-ui-kit/components/tag";
export function DraftTags() {
const [tags, setTags] = useState(["design", "q3"]);
return (
<div style={{ display: "flex" }}>
{tags.map((tag, index) => (
<Tag
key={tag}
tag={tag}
label={tag}
isNewTag
isLast={index === tags.length - 1}
onDelete={(name) => setTags((t) => t.filter((x) => x !== name))}
/>
))}
</div>
);
}
A provider tag, icon only
withLabel={false} leaves the glyph on its own — this is how a third-party storage is marked.
import { Tag } from "@onlyoffice/apps-ui-kit/components/tag";
export function ProviderTag({ iconUrl }: { iconUrl: string }) {
return (
<Tag
tag="provider"
label="Nextcloud"
icon={iconUrl}
withLabel={false}
providerType={3}
/>
);
}
Behaviour the types don't state
onClickreceives{ label, roomType, providerType }, not an event.labelfalls back totagwhen you did not pass one, so the handler always has something to filter by.- The delete cross is drawn only when
isNewTagis set.onDeleteon its own does nothing, which is the usual reason a tag looks un-removable. isDeletedandisDisableddo not restyle the text. The stylesheet has rules for a struck-through label and a greyed one, but the class they need is never put on the text, so only the border changes. Do not rely on either state being legible on its own.isDisabledalso blocks hover, because the CSS setspointer-events: noneon the whole tag — a tooltip attached to it will not open.- The clickable area is bigger than the tag. A pseudo-element extends it 3px on every side and 28px tall, so two tags closer than that overlap in their hit areas.
- The tag brings its own trailing margin of 4px, which
isLastremoves. In a flex row with agapthe two add up. - Hover highlights the tag only when
onClickis passed. Without a handler the tag keeps its colours and the default cursor under the pointer; a disabled or deleted tag never highlights. - The tag is
width: fit-contentand capped at 22px tall.tagMaxWidthis written into the inline style, afterstyle, so it wins over amaxWidthset there. A label wider than that cap is cut off with an ellipsis, and the full text stays in thetitletooltip. - A component passed as
iconis rendered inside anIconButtonat 12px and the tag's padding drops to 0; a string is fetched and inlined instead. The two forms do not look the same. isDefaultis declared onTagPropsand never read — it isTagType.isDefault, the shapeTagstakes, that has an effect.- The
titleattribute and the accessible name are bothlabel, so a tag with no label has neither.
CSS variables
Set them on any ancestor.
--tag-bg is the resting background only: a new tag, and any clickable tag on hover or press,
takes its theme colour instead. Likewise --tag-border-style gives way to the dashed theme
border on a disabled tag. --tag-height is a max-height, so raise it together with the
vertical part of --tag-inner-padding for a taller tag.
--tag-text-color, --tag-size and --tag-lh are read by the same label class the
isDeleted and isDisabled text rules need, which is never put on the text, so today they
change nothing. The other --tag-* names the stylesheet
uses (--tag-background, --tag-color and the rest) are declared by the theme on the tag
itself, so a wrapper cannot override them.
Accessibility
- The tag is a
<div>with a click handler andaria-labelset fromlabel. It has no role and notabIndex, so a clickable tag cannot be reached or activated from the keyboard. aria-disabledis set fromisDisabled, and the CSS additionally makes the tag inert.- The delete cross is an
IconButton, which is itself a<div>with no name — nothing announces which tag it removes, and it cannot be focused. - A tag with
withLabel={false}announces only itsaria-label, so keeplabelfilled in even when it is not drawn.
Test ids
Tags overrides it per tag with tag_item_<label>.
Related
Tags— the row that lays these out and handles the overflow.SelectedItem— the removable chip for a user's own choice.Badge— the filled pill for a count or a status.