Label
Caption for a form field, with an optional required asterisk and an error colour. It is a
<label> element rendered through Text at weight 600.
Use this when / not when
- Use to caption a field you have laid out yourself, tying the two together with
htmlFor. - Not inside
FieldContainer— it renders its own label fromlabelText, and a second one would double the caption. - Not for a line of text that captions nothing.
Textis that; a<label>with no field attached is noise for a screen reader. - Not to show a validation message.
erroronly recolours the caption; the message is yours to render.
Import
import { Label } from "@onlyoffice/apps-ui-kit/components/label";
Also exported from the root barrel @onlyoffice/apps-ui-kit.
LabelProps is not exported — type a wrapper's props yourself.
Needs ThemeProvider from @onlyoffice/apps-ui-kit/providers/theme for the text colour.
Stories
Default
The plain caption for a field, in semibold text; rest the pointer on it to read the tooltip (title), and change any other prop live in the Controls panel below.
Required Labels
For fields a form cannot be sent without: each caption ends with a red asterisk (isRequired). The asterisk is hidden from screen readers, so the input needs required as well.

Error State
For a field that failed validation: the caption turns red (error), with or without the asterisk. The error message is not part of the label; render it next to the field.
Truncated Label
For a caption longer than the space it gets: in a 150px box the text stays on one line and ends with an ellipsis (truncate, with display: block so the label takes the box's width). Rest the pointer on it to read the full text in the tooltip (title), which needs RootTooltip mounted, as this story does.
Inline Label
For a caption beside its field rather than above it: the label sits on the same line as the input (isInline).
With Children
For a note that belongs to the caption, such as "(optional)": content passed as children follows the text inside the same label (children).
Form Example
How the states read together in a form: a required field, a required field in error and an optional one, each label tied to its input by htmlFor, so clicking a caption focuses its field.
Css Customization
Both colours and the font size set on one wrapper -- the variables are listed under CSS variables on this page.
- Display name shows the asterisk colour (
--label-required-color) and the font size. - Email address adds
errorto show the text colour in the error state (--label-error-color).
Minimal example
htmlFor is what makes the caption clickable and announces it with the field; without it this
is a styled paragraph.
import { Label } from "@onlyoffice/apps-ui-kit/components/label";
import {
InputSize,
InputType,
TextInput,
} from "@onlyoffice/apps-ui-kit/components/text-input";
export function NameField({
value,
onChange,
}: {
value: string;
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
}) {
return (
<div>
<Label
text="First name"
htmlFor="first-name"
style={{ display: "block" }}
isRequired
/>
<TextInput
id="first-name"
type={InputType.text}
size={InputSize.base}
value={value}
onChange={onChange}
required
/>
</div>
);
}
Props
Recipes
Error
error recolours the caption and sets aria-invalid on it. Pair it with the field's own
hasError and a message of your own — the label prints neither.
import { Label } from "@onlyoffice/apps-ui-kit/components/label";
import { Text } from "@onlyoffice/apps-ui-kit/components/text";
import {
InputSize,
InputType,
TextInput,
} from "@onlyoffice/apps-ui-kit/components/text-input";
export function EmailField({
value,
problem,
onChange,
}: {
value: string;
problem?: string;
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
}) {
return (
<div>
<Label
text="Email"
htmlFor="email"
style={{ display: "block" }}
error={Boolean(problem)}
/>
<TextInput
id="email"
type={InputType.email}
size={InputSize.base}
value={value}
onChange={onChange}
hasError={Boolean(problem)}
/>
{problem ? <Text fontSize="12px">{problem}</Text> : null}
</div>
);
}
Behaviour the types don't state
- It has no margin of its own. The label sits flush against whatever follows it; the gap is
yours to add.
FieldContaineris the component that brings spacing. - A space is always rendered between the text, the asterisk and the children, because the three are joined with literal spaces in the markup. A child meant to sit tight against the text will not.
aria-requiredandaria-invalidare set on the label, not on the field. Assistive technology reads those states from the input, so setrequiredandaria-invalidthere as well; the label's copies are decoration.- The asterisk is
aria-hidden, so "required" reaches a screen reader only through the field's ownrequired. truncateneeds a block and a width. It setstext-overflow: ellipsison a<label>, which is inline and as wide as its content, so on its own it changes nothing. Give itstyle={{ display: "block" }}and a width, or a parent that constrains one.displayis not CSS. It lands on the element as an HTMLdisplayattribute and leaves the layout alone;style={{ display: "block" }}is what puts the label on its own line.isInlinemakes an inline block, not an inline element — the label already is one. The block keeps its own width and padding on the line beside the field.titleopens the kit's shared tooltip, not the browser's. Once mounted, the label drops the nativetitleattribute and opens the tooltip rendered byRootTooltipwhen the pointer rests on it; with noRootTooltipon the page nothing appears at all.errorwins over anycolorthe theme would apply, and uses--label-error-colorwith the kit's error red as the fallback.tooltipMaxWidthis dead. Nothing reads it, and the shared tooltip sizes itself.
CSS variables
| Variable | Default | Effect |
|---|---|---|
--label-error-color | kit error red (#F24724) | Colour of the text when error |
--label-required-color | kit error red (#F24724) | Colour of the required asterisk |
--text-size | 13px | Font size; read by Text, not here |
Both colours fall back to the light theme's error red in either theme; set them yourself for a dark one.
Accessibility
htmlForis the whole point: without it the element is a<label>attached to nothing, and clicking it does not focus the field.- Set
requiredon the input as well asisRequiredhere — the asterisk is hidden from assistive technology on purpose, andaria-requiredon a label is not announced. - The same holds for
error: the field needs its ownaria-invalid, and the message needs to be tied to it witharia-describedby. truncatehides text visually but keeps it in the accessibility tree;titlegives pointer users the full string back in the shared tooltip, and no one else — it is not a nativetitlea screen reader could read.
Test ids
Neither can be overridden by a prop.
Related
FieldContainer— label, field and error message together.Text— what this renders through.TextInput— the field this most often captions.