AddButton
Square icon button with an optional label beside it, for adding one more of something. It is the "add members" affordance of the portal's selectors: a 32px tile with a plus in it.
Use this when / not when
- Use for adding an item to a list the user is building — a member, a tag, a share.
- Not for a form's submit or a dialog's action;
Buttonhas the sizes and the primary look. - Not for an icon action with no "add" meaning —
IconButtonis the bare icon. - Not for choosing from a prepared list, which is what
Selectoris for; this is the button that opens one.
Import
import { AddButton } from "@onlyoffice/apps-ui-kit/components/add-button";
Also exported from the root barrel @onlyoffice/apps-ui-kit.
Needs ThemeProvider from @onlyoffice/apps-ui-kit/providers/theme. It reads the colour
scheme directly, not only the theme class — isAction and size do nothing without one.
Stories
Default
The bare square with a plus, for a list that needs one more item and has room for no label. Click it, or press Tab and then Enter, and the Actions panel logs the call (onClick, tabIndex); change any other prop live in the Controls panel below.
With Label
A label says what gets added when a bare plus would leave the reader guessing, and clicking the words adds too. Add user is the grey square; Add group is the accent tint (isAction).
Disabled States
A disabled button stays in place so the reader sees the action exists but is not available now: the square turns a lighter grey, the icon greys out and the label dims, and clicks and Enter are ignored (isDisabled).
Accent Style
The accent tint marks the add button that matters most on a screen. Default is the grey square; Accent is tinted with the theme's accent colour (isAction).
Loading State
While the item is being added, a spinner stands in for the icon so a second click does not add it twice; clicks are ignored until loading ends, and the square keeps its size (isLoading).
Truncated Label
In a narrow column a long label is cut with an ellipsis instead of wrapping under the square; the parent here is 150px wide (truncate).
Custom Icon Size
A bigger square and icon suit a roomier layout. Default is the 32px square with a 12px icon; Large icon is a 36px square (size) with a 16px icon (iconSize).
With Custom Icon
When a plus does not say enough about what gets added, the square can carry any icon; here a folder icon at 16px (iconNode, iconSize). An icon given by URL is fetched at runtime instead (iconName).
Css Customization
Every overridable variable set on one wrapper -- the variables are listed under CSS variables on this page.
Add item shows the square, icon and gap variables; hover and press it near its edge to see the hover and active colours. Disabled is there for --add-button-text-disabled, the only variable that survives the disabled state: the theme draws its square and icon in its own greys.
Minimal example
tabIndex is what makes the button focusable; it has no default.
import { AddButton } from "@onlyoffice/apps-ui-kit/components/add-button";
export function AddMember({ onAdd }: { onAdd: () => void }) {
return <AddButton label="Add member" tabIndex={0} onClick={onAdd} />;
}
Props
Recipes
Loading
isLoading swaps the icon for a spinner and drops the click. The square keeps its size, so the
row does not jump.
import { AddButton } from "@onlyoffice/apps-ui-kit/components/add-button";
export function AddMemberPending({
pending,
onAdd,
}: {
pending: boolean;
onAdd: () => void;
}) {
return (
<AddButton
label="Add member"
tabIndex={0}
isLoading={pending}
onClick={onAdd}
/>
);
}
Disabled / read-only
isDisabled greys the icon, dims the label and stops the click — including the Enter key.
import { AddButton } from "@onlyoffice/apps-ui-kit/components/add-button";
export function AddMemberLocked() {
return <AddButton label="Add member" isDisabled onClick={() => {}} />;
}
An icon of your own
iconNode replaces the plus with any element; iconName takes a URL instead, which the
kit fetches at runtime.
import { AddButton } from "@onlyoffice/apps-ui-kit/components/add-button";
export function AddTag({ onAdd }: { onAdd: () => void }) {
return (
<AddButton
label="New tag"
tabIndex={0}
onClick={onAdd}
iconSize={16}
iconNode={
<svg viewBox="0 0 16 16" aria-hidden="true">
<path d="M8 3v10M3 8h10" stroke="currentColor" strokeWidth="1.5" />
</svg>
}
/>
);
}
Behaviour the types don't state
- Keyboard support is opt-in. The wrapper carries
role="button"and an Enter handler, but notabIndexunless you pass one — without it the button cannot be focused and the handler never runs. Enter is ignored whileisDisabledorisLoadingis set, and Space does nothing in either case. isActionneeds a colour scheme, not just a theme. The accent tint is written as an inline custom property from the theme'scurrentColorScheme.main.accent; when the provider has none, that property is never set and the rulebackground-color: var(--main-accent-button) !importantleaves the square transparent.sizeshares that fate. It is only written when the colour scheme exists, so under a provider without one the square stays 32×32 whatever you pass.titleis the kit's tooltip,titleTextis the browser's. The first goes through the tooltip wrapper and is drawn by the kit on hover; the second is a plaintitleattribute on the label.idandstyleland on the square, not on the wrapper, whileclassNamelands on the wrapper — the three are not applied to the same element.- The label is part of the click target. It is a
Textwith the same handler, so clicking the words adds too. - The square is 32×32 with 10px of padding, and the icon inside it defaults to 12px, so a
larger
iconSizeeats into the padding rather than growing the square. - The wrapper is
display: flexwith no gap; the label's 8px of spacing is its ownpadding-inline-start, from--add-button-text-gap. truncateneeds a bounded parent. It setsmin-width: 0on the wrapper and lets the label ellipsis, which only shows up when something upstream limits the width.- Without
iconNodeand withouticonNamethe default plus is drawn — the button is never empty.
CSS variables
Set them on any ancestor.
isActionandisDisabledoverride the square's colours. UnderisActionthe background and the icon take the accent colour, and while disabled the theme's own greys are forced with!important, so--add-button-bgand--add-button-icon-color(and their hover and pressed forms) no longer apply.--add-button-text-disabledis the only variable that survives the disabled state.- The icon's hover fill only shows around the icon. With the pointer over the icon itself,
IconButton's own hover colour is the more specific rule and wins over--add-button-icon-color-hoverand--add-button-icon-color-active.
Accessibility
- The wrapper is a
<div role="button">with an Enter handler. That is enough for a screen reader to announce it as a button only if you passtabIndex; Space still does nothing, which a real button would handle. - There is no accessible name unless you provide one.
labelis rendered as ordinary text inside the same wrapper, so it does name the button — but a button withoutlabelhas none, andtitledoes not supply it. aria-disabledis not set. A disabled button is still announced as an ordinary button; only the click and the Enter key are dropped.- The icon square itself is an
IconButtoninside the wrapper, which is a<div>with no role of its own.
Test ids
Only the square's id can be overridden, through testId rather than dataTestId.
Related
IconButton— the icon alone, with no tile behind it.Button— the full-size button with a label inside it.Selector— the list this button usually opens.