SelectedItem
Chip with a cross, for a value the user has picked and can take back. It is what a filter
draws under its input for every active condition, and what DatePicker
becomes once a date is chosen.
Use this when / not when
- Use for a choice the user made and can undo — a filter term, a selected author, a chosen date — where removing it is a first-class action.
- Not as a label on data the user did not choose;
Tagis the room tag, smaller and without the removal semantics. - Not as a toggle in a group of options —
TabItemis the selectable pill, andCheckboxthe honest form control. - Not for one-off text with a colour;
Badgeis that.
Import
import { SelectedItem } from "@onlyoffice/apps-ui-kit/components/selected-item";
Also exported from the root barrel @onlyoffice/apps-ui-kit.
Needs ThemeProvider from @onlyoffice/apps-ui-kit/providers/theme; without it the chip has
no background and the disabled colours resolve to nothing.
Stories
Default
The chip as a filter shows a picked value: click the cross to see onClose in the Actions panel, click the label for onClick, and change any other prop live in the Controls panel below.
Disabled State
For a value the user may see but not take back: the label and the cross grey out and neither handler fires (isDisabled).
Block Display
For a list of picked values stacked one per row: the chip fills the width of its container and pushes the cross to the far end (isInline={false}).
All Variants
How the modes sit together in a filter bar:
- Inline enabled and Another item — inline chips wrapping in a row
- Inline disabled — the same chip with its label and cross greyed out (
isDisabled) - Block display item — a chip that fills the row (
isInline={false})

With Icon
For a value that is easier to recognise by its kind: a glyph sits before the label (icon, here an SVG component; an SVG URL works too).
Active State
For the chip the user is working with right now: the background tints and the label and icon take the accent colour (isActive).
Without Cross
For a value the user can pick but not remove from the chip itself: the cross is left out and only a click on the chip is reported (hideCross).
Truncated Label
For values longer than a chip can hold: the label is cut off with an ellipsis; rest the pointer on the chip to read the full text in the tooltip (title). The tooltip is the kit's shared one, so the app must mount RootTooltip once, as this story does.
Css Customization
Every overridable variable set on one wrapper -- the variables are listed under CSS variables on this page. The example has three chips: Custom item for the colours and sizes (hover it for the hover background), Disabled for --selected-item-disabled-text (isDisabled), and Active for the two active variables (isActive).

Minimal example
onClose is handed the propKey you gave the chip, so one handler serves a whole list.
import { useState } from "react";
import { SelectedItem } from "@onlyoffice/apps-ui-kit/components/selected-item";
export function ActiveFilters() {
const [terms, setTerms] = useState(["Reports", "2026", "PDF"]);
return (
<div style={{ display: "flex", flexWrap: "wrap" }}>
{terms.map((term) => (
<SelectedItem
key={term}
label={term}
propKey={term}
onClose={(key) => setTerms((t) => t.filter((x) => x !== key))}
/>
))}
</div>
);
}
Props
Recipes
Disabled / read-only
isDisabled greys the label and stops both handlers. The cross is still drawn — use
hideCross to take it away for a chip that cannot be removed at all.
import { SelectedItem } from "@onlyoffice/apps-ui-kit/components/selected-item";
export function FixedScope({ scope }: { scope: string }) {
return (
<SelectedItem
label={scope}
propKey="scope"
title="Set by your administrator"
isDisabled
hideCross
onClose={() => {}}
/>
);
}
A chip that is also a button
onClick fires for a click on the chip, so the same chip can open the filter it stands for
and remove it. A click on the cross reaches onClick too, after onClose (see below), so the
handler here only toggles state the removal makes irrelevant.
import { useState } from "react";
import { SelectedItem } from "@onlyoffice/apps-ui-kit/components/selected-item";
export function AuthorFilter() {
const [author, setAuthor] = useState<string | null>("Anna Ivanova");
const [editing, setEditing] = useState(false);
if (!author) return null;
return (
<div>
<SelectedItem
label={author}
propKey="author"
group="people"
isActive={editing}
onClick={() => setEditing((v) => !v)}
onClose={() => setAuthor(null)}
/>
{editing ? <p>Pick another author</p> : null}
</div>
);
}
Behaviour the types don't state
- A falsy
labelrenders nothing. The component returnsnullbefore anything else, so a chip whose label has not loaded yet disappears rather than showing an empty box. onCloseandonClickare not given the DOM event first. Both start withpropKeyandlabel; the event is the fourth argument andonClosereceives""forgroupwhen you did not set one.- A click on the cross fires
onCloseand thenonClick. The chip skipsonClickonly when the clicked element itself carriesselected-tag-removed, the class the component puts on the cross's own box — but that box is filled by the cross's SVG, so a real click lands on the<path>and bubbles up to the chip.classNameCloseButtonis added beside that class, never instead of it. Where a click on the chip must not follow a removal, haveonClickignore a keyonClosehas just removed. - The chip brings its own spacing:
margin-inline-end: 4pxandmargin-bottom: 4px. In a flex row with agapthose add up; set--selected-item-margin-inlineand--selected-item-margin-bottomto0if the gap should be the only spacing. isInlinedefaults to true and is what keeps the chip narrow. PassingisInline={false}makes itwidth: 100%, which is the block form used in a side panel.- The label is capped at 23 characters (
max-width: 23ch) and truncated with an ellipsis. Passtitleso the full text is available on hover. titleopens the kit's shared tooltip, not the browser's. Once mounted, the chip renders notitleattribute; it is marked as a tooltip anchor, and the text shows only where the app has mountedRootTooltiponce. Without it nothing appears on hover. UnderNODE_ENV=testa nativetitleattribute is rendered instead.iconaccepts either a URL or a component. A string is fetched and inlined byreact-svg; a component is rendered with no props at all, so an icon that needs a size has to carry it itself.styleandclickableare declared and never read. UseclassNameand the custom properties, and passonClickto make the chip clickable.- The exported
SelectedItemPureis the same component withoutReact.memo.
CSS variables
Set them on any ancestor.
Accessibility
- The chip is a
<div>with a click handler. It has no role, notabIndexand no key handler, soonClickis unreachable from the keyboard. - The cross is an
IconButton, which is also a<div>with no role, no name and notabIndex. A keyboard-only user cannot remove a chip, and a screen reader is told nothing about what the cross does. Where removal has to be reachable, render your ownButtonbeside the chip and passhideCross. titlefeeds the shared pointer tooltip and leaves notitleattribute on the chip, so it is not a label either.isDisabledis a colour and a guard in the handlers. Noaria-disabledis set on the chip, so assistive technology is not told it is inert; only the cross carriesaria-disabled,truewhileisDisabledandfalseotherwise.
Test ids
The cross's id comes from IconButton and cannot be set from here;
query it by the selected-tag-removed class instead when there are several chips.
Related
Tag— the room tag, for labels the user did not pick.DatePicker— draws its chosen date as one of these.IconButton— the cross.