Skip to main content

InputBlock

Text field with an icon at the end and room for a prefix before it, inside one border. It wraps TextInput and IconButton in a group that draws the border for them.

InputBlockInputBlock

Use this when / not when​

  • Use for a field that needs an affordance at its end — a clear cross, a reveal eye, a picker — or a fixed prefix in front of it.
  • Not for a plain field. TextInput is that, and this always renders the icon box unless you say noIcon.
  • Not for search — SearchInput is this component with the search and clear behaviour already wired, and its onChange gives you a string.
  • Not for a password — PasswordInput adds the reveal toggle and the strength rules.

Import​

import { InputBlock } from "@onlyoffice/apps-ui-kit/components/input-block";

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

Needs ThemeProvider from @onlyoffice/apps-ui-kit/providers/theme for the border and background colours.

Stories​

Default​

A text field with a search icon at its end, inside one border. Type in it, and change any other prop live in the Controls panel below.

DefaultDefault

Sizes​

Match the field to the controls around it: Base size, Middle size and Large size differ in text size, padding and the height of the icon box (size).

SizesSizes

States​

How the field reads in each state: Error state and Warning state recolour the border of the whole group (hasError, hasWarning); Disabled greys the field out and drops the icon (isDisabled); Read-only content keeps the look and the icon and only stops typing (isReadOnly).

StatesStates

Password Type​

For a secret that must not be read off the screen, the typed characters are masked (type={InputType.password}). For a reveal toggle and strength rules, use PasswordInput instead.

Password TypePassword Type

With Icon Click​

An icon that does something, such as clearing the field or opening a picker, needs a click handler (onIconClick); without it the icon is drawn greyed out and ignores clicks, as in the other stories. Click the search icon to see the action.

With Icon ClickWith Icon Click

With Prefix​

A fixed part of the value that the user does not type sits in front of the input, inside the same border (children). Amount has a currency sign and no icon at its end (noIcon); Phone number has a country code and keeps its icon.

With PrefixWith Prefix

Right To Left​

The same field under a right-to-left interface: the icon moves to the left end, the prefix to the right end, and the placeholder sits at the right edge. The direction comes from the theme's interfaceDirection (the Direction toolbar); the wrapper also carries dir="rtl" for the rules that read the DOM direction.

Right To LeftRight To Left

Css Customization​

Every overridable variable set on one wrapper -- the variables are listed under CSS variables on this page.

Amount carries a prefix, for the prefix padding, and shows every other variable except the large icon padding; Large size is there for --input-block-icon-padding-lg, which only the large size reads. Hover and focus a field to see the hover and focus border colours.

Css CustomizationCss Customization

Minimal example​

type, value and onChange are the three that matter; tabIndex is the one that will catch you out, because it defaults to -1.

import { useState } from "react";
import { InputBlock } from "@onlyoffice/apps-ui-kit/components/input-block";
import {
InputSize,
InputType,
} from "@onlyoffice/apps-ui-kit/components/text-input";

export function RoomName() {
const [name, setName] = useState("");

return (
<InputBlock
type={InputType.text}
size={InputSize.base}
value={name}
placeholder="Room name"
tabIndex={0}
scale
iconNode={<span aria-hidden="true">×</span>}
onIconClick={() => setName("")}
onChange={(event) => setName(event.target.value)}
/>
);
}

Props​

PropertyTypeDescription
children?React.ReactNodeRendered before the input, inside the same bordered group — a currency sign, a country code, a fixed prefix.
className?stringApplied to the group.
dataTestId?stringdata-testid of the group. Default: "input-block".
forwardedRef?React.Ref<HTMLInputElement>Ref to the <input> element itself.
hoverColor?stringColour of that icon on hover.
iconButtonClassName?stringApplied to the box around the icon. Default: "".
iconColor?stringColour of that icon.
iconName?stringURL of the icon at the end of the field. Default: "".
iconNode?React.ReactNodeThe icon as an element, instead of iconName.
iconSize?numberSize of that icon in pixels. It falls back to size.
id?stringApplied to the <input>, not to the group around it.
isIconFill?booleanWhether the icon's paths are recoloured to iconColor. Leave it off for a multi-coloured icon. Default: false.
noIcon?booleanWhether the icon box is left out entirely. Without it an empty box is still rendered and still takes its padding. Default: false.
onIconClick?(e: React.MouseEvent) => voidCalled when the icon is clicked. Without it the icon is rendered in the disabled style and does not respond — it is what makes the icon a button.
style?React.CSSPropertiesApplied to the group.
tabIndex?numberUsed as HTML tabindex property of the <input>. Unlike TextInput's, this one defaults to -1, so the field is out of the tab order until you pass 0 — and so is every component built on it that passes its own tabIndex through, SearchInput and PasswordInput among them. Default: -1.
testId?stringdata-testid of the inner <input>, passed through to TextInput.

Inherited from TextInputProps​

Declared by components/text-input and accepted here too.

PropertyTypeDescription
typeInputTypeSupported type of the input fields
valuestringValue of the input
autoComplete?stringUsed as HTML autocomplete property. Default: "off".
dir?stringText direction. Default: "auto".
fontWeight?number | stringSets the font weight
guide?booleanWhen guide is true, Text Mask always shows both placeholder characters and non-placeholder mask characters
hasError?booleanIndicates the input field has an error
hasWarning?booleanIndicates the input field has a warning
inputMode?"decimal" | "email" | "none" | "numeric" | "search" | "tel" | "text" | "url"Input mode for virtual keyboard
isAutoFocussed?booleanFocus the input field on initial render
isBold?booleanSets font weight value to 600
isDisabled?booleanIndicates that the field cannot be used
isReadOnly?booleanIndicates that the field is displaying read-only content
keepCharPositions?booleanAllows to add or delete characters without changing the positions of the existing characters
mask?((value: string) => Mask) | MaskInput text mask
maxLength?numberMaximum number of characters the field accepts; further typing is silently dropped. Default: 255.
name?stringUsed as HTML name property
onBlur?(e: React.FocusEvent<HTMLInputElement>) => voidCalled when field is blurred
onChange?(e: React.ChangeEvent<HTMLInputElement>) => voidCalled with the new value. Required when input is not read only
onClick?(e: React.MouseEvent<HTMLInputElement>) => voidCalled when clicked
onContextMenu?(e: React.MouseEvent<HTMLInputElement>) => voidCalled when context menu is triggered
onFocus?(e: React.FocusEvent<HTMLInputElement>) => voidCalled when field is focused
onKeyDown?(e: React.KeyboardEvent<HTMLInputElement>) => voidCalled when a key is pressed
placeholder?stringPlaceholder text for the input. The default is a single space, not an empty string, so :placeholder-shown matches even when no placeholder was asked for. Default: " ".
scale?booleanIndicates the input field has scale
size?InputSizeSupported size of the input fields
spellCheck?booleanUsed as HTML spellcheck property
withBorder?booleanIndicates that component contains border

Plus 299 more props inherited from React.AriaAttributes, React.DOMAttributes, React.HTMLAttributes and React.InputHTMLAttributes, forwarded to the element.

Enums​

EnumMembers
InputSizebase, middle, large
InputTypetext, password, email, tel, search, number

Recipes​

Disabled / read-only​

isDisabled greys the group and removes the icon entirely, so a field whose icon carries meaning changes shape when it is disabled. isReadOnly keeps the icon and the field's look, and only stops the typing.

import { InputBlock } from "@onlyoffice/apps-ui-kit/components/input-block";
import {
InputSize,
InputType,
} from "@onlyoffice/apps-ui-kit/components/text-input";

export function PortalAddress({ address }: { address: string }) {
return (
<InputBlock
type={InputType.text}
size={InputSize.base}
value={address}
isReadOnly
tabIndex={0}
scale
iconNode={<span aria-hidden="true">⧉</span>}
onIconClick={() => navigator.clipboard.writeText(address)}
onChange={() => {}}
/>
);
}

Error​

hasError and hasWarning recolour the group's border. Neither prints a message; that is FieldContainer's job, or yours.

import { useState } from "react";
import { FieldContainer } from "@onlyoffice/apps-ui-kit/components/field-container";
import { InputBlock } from "@onlyoffice/apps-ui-kit/components/input-block";
import {
InputSize,
InputType,
} from "@onlyoffice/apps-ui-kit/components/text-input";

export function PortName() {
const [port, setPort] = useState("");
const problem = port && Number.isNaN(Number(port)) ? "Digits only" : "";

return (
<FieldContainer
isVertical
labelVisible
labelText="Port"
hasError={Boolean(problem)}
errorMessage={problem}
>
<InputBlock
type={InputType.text}
size={InputSize.base}
value={port}
hasError={Boolean(problem)}
tabIndex={0}
scale
noIcon
onChange={(event) => setPort(event.target.value)}
/>
</FieldContainer>
);
}

A prefix in front of the field​

children are rendered before the input, inside the same border.

import { useState } from "react";
import { InputBlock } from "@onlyoffice/apps-ui-kit/components/input-block";
import { Text } from "@onlyoffice/apps-ui-kit/components/text";
import {
InputSize,
InputType,
} from "@onlyoffice/apps-ui-kit/components/text-input";

export function Subdomain() {
const [name, setName] = useState("");

return (
<InputBlock
type={InputType.text}
size={InputSize.base}
value={name}
tabIndex={0}
scale
noIcon
onChange={(event) => setName(event.target.value)}
>
<Text style={{ paddingInline: 8 }}>https://</Text>
</InputBlock>
);
}

Behaviour the types don't state​

  • tabIndex defaults to -1, so the field is out of the tab order unless you pass 0. This is the single thing most likely to go wrong: the input looks right and the keyboard never reaches it.
  • The icon box is always rendered. Without iconName or iconNode you still get an empty box with its padding, and the field is narrower than it looks. Pass noIcon for a plain field.
  • An icon without onIconClick is drawn in the disabled style. The inner IconButton is given isDisabled whenever no handler is passed, so a purely decorative icon comes out greyed.
  • isDisabled removes the icon, rather than disabling it — the whole box is dropped from the markup, so the field changes width when it is disabled.
  • The border belongs to the group, not the input. withBorder: false is forced on the inner TextInput, which is why hasError, hasWarning and the focus ring are drawn around everything including the prefix and the icon.
  • maxLength defaults to 255 and autoComplete to "off", both inherited from the same decision in TextInput.
  • value is required and the field is controlled, so it needs an onChange from the first render to be typeable at all.
  • It is not scaled by default: the field has TextInput's own base width until you pass scale, even though the group around it is 100% wide.
  • size reaches the icon box too. Besides the text size and padding of the field, it sets the icon box to the field's line height, and at large the space after the icon grows from --input-block-icon-padding to --input-block-icon-padding-lg. An unset size leaves the box at its content's height.
  • type is passed straight to the inner <input>, so password masks the text and email or tel bring up the matching keyboard on a phone.
  • id goes on the inner <input> while className and style go on the group, so a htmlFor pointing at id reaches the real field.
  • children are wrapped in two nested boxes of their own, both inheriting the group's background, so a prefix sits flush inside the border.

CSS variables​

VariableDefaultEffect
--input-block-icon-padding8pxSpace after the icon at base and middle; one length, not a shorthand
--input-block-icon-padding-lg12pxThe same at the large size; only large reads it
--input-block-icon-start1pxSpace before the icon; one length
--input-block-children-padding2px 0 2px 2pxPadding around the prefix, as a padding shorthand
--text-input-bg--input-bgBackground of the group and the field
--text-input-color--input-colorText colour
--text-input-border-color--input-border-colorBorder colour of the group at rest
--text-input-border-hover--input-border-hoverBorder colour of the group while hovered
--text-input-border-focus--input-border-focusBorder colour of the group while the field has focus
--text-input-radius--input-border-radiusCorner radius of the group
--text-input-font-size13px (16px at large)Font size of the field, at every size at once

The --text-input-* variables come from the shared input styles, so they mean what they mean for TextInput; here the group reads them, because the inner field draws no border of its own. Set them on the group or any ancestor.

Accessibility​

  • Pass tabIndex={0}. The default of -1 takes a working text field out of the keyboard's reach, which is the most severe accessibility defect in this component.
  • The icon is an IconButton inside a clickable <div>; give it a name through your own markup, since nothing here labels it.
  • The field has no label of its own. Use FieldContainer, or a Label with htmlFor pointing at id.
  • hasError only changes a colour. Tie a message to the field with aria-describedby and set aria-invalid yourself.
  • A prefix in children is read before the field, which is usually right — but it is not part of the field's accessible name.

Test ids​

Elementdata-testid
The groupinput-block, or dataTestId
The inputtestId, passed to TextInput
  • TextInput — the field inside, and where its props are documented.
  • SearchInput — this component with search behaviour attached.
  • PasswordInput — this component with a reveal toggle.