Data input
Input Group
One input with icons, text or buttons inside its border, either inline or as joined addon segments.
| Class name | Type | Description |
|---|---|---|
input-groupplf:input-group | Component | An input with icons, text or buttons inside its border |
input-group-controlplf:input-group-control | Part | The native input |
input-group-textplf:input-group-text | Part | Short text before or after the input |
input-group-iconplf:input-group-icon | Part | A decorative SVG icon; an icon class there doesn't need it |
input-group-actionplf:input-group-action | Part | A button inside the group |
input-group-addonplf:input-group-addon | Part | An affix joined as a muted segment |
input-group-comboboxplf:input-group-combobox | Part | A Combobox joined as a segment |
input-group-smplf:input-group-sm | Size | Small |
input-group-lgplf:input-group-lg | Size | Large |
input-group-custom-clearplf:input-group-custom-clear | Modifier | Hides the browser's own clear button on a search input |
A decorative trailing icon; this example does not search a service.
<div class="field">
<label class="field-label" for="group-member">Find a member</label>
<div class="input-group">
<input class="input-group-control" id="group-member" type="search" placeholder="Member name" aria-describedby="group-member-help">
<span class="icon icon-search"></span>
</div>
<p class="field-help" id="group-member-help">A decorative trailing icon; this example does not search a service.</p>
</div><div class="plf:field">
<label class="plf:field-label" for="group-member">Find a member</label>
<div class="plf:input-group">
<input class="plf:input-group-control" id="group-member" type="search" placeholder="Member name" aria-describedby="group-member-help">
<span class="plf:icon plf:icon-search"></span>
</div>
<p class="plf:field-help" id="group-member-help">A decorative trailing icon; this example does not search a service.</p>
</div>import { Field, Icon, InputGroup, InputGroupControl } from '@pelatform/react';
export function Example() {
return (
<Field label="Find a member" help="A decorative trailing icon; this example does not search a service.">
<InputGroup>
<InputGroupControl type="search" placeholder="Member name" />
<Icon name="search" />
</InputGroup>
</Field>
);
}import { Field, Icon, InputGroup, InputGroupControl } from '@pelatform/react/prefixed';
export function Example() {
return (
<Field label="Find a member" help="A decorative trailing icon; this example does not search a service.">
<InputGroup>
<InputGroupControl type="search" placeholder="Member name" />
<Icon name="search" />
</InputGroup>
</Field>
);
}Clear button
data-plf-clear shows the button while the field holds a value; it empties the field and returns focus to it. An empty clear button draws an x.
Clear resets this field and returns focus to it; no remote search.
<div class="field">
<label class="field-label" for="group-search">Search components</label>
<div class="input-group input-group-custom-clear">
<span class="icon icon-search"></span>
<input class="input-group-control" id="group-search" type="search" value="Button" aria-describedby="group-search-help">
<button class="input-group-action" data-plf-clear hidden></button>
</div>
<p class="field-help" id="group-search-help">Clear resets this field and returns focus to it; no remote search.</p>
</div><div class="plf:field">
<label class="plf:field-label" for="group-search">Search components</label>
<div class="plf:input-group plf:input-group-custom-clear">
<span class="plf:icon plf:icon-search"></span>
<input class="plf:input-group-control" id="group-search" type="search" value="Button" aria-describedby="group-search-help">
<button class="plf:input-group-action" data-plf-clear hidden></button>
</div>
<p class="plf:field-help" id="group-search-help">Clear resets this field and returns focus to it; no remote search.</p>
</div>import { Field, Icon, InputGroup, InputGroupClear, InputGroupControl } from '@pelatform/react';
export function Example() {
return (
<Field label="Search components" help="Clear resets this field and returns focus to it; no remote search.">
<InputGroup customClear>
<Icon name="search" />
<InputGroupControl type="search" defaultValue="Button" />
<InputGroupClear />
</InputGroup>
</Field>
);
}import { Field, Icon, InputGroup, InputGroupClear, InputGroupControl } from '@pelatform/react/prefixed';
export function Example() {
return (
<Field label="Search components" help="Clear resets this field and returns focus to it; no remote search.">
<InputGroup customClear>
<Icon name="search" />
<InputGroupControl type="search" defaultValue="Button" />
<InputGroupClear />
</InputGroup>
</Field>
);
}Password toggle
data-plf-password-toggle shows or hides the password and keeps the selection; it draws an eye, crossed out while the password shows. Two icons of yours take its place: the first, and the second while the password shows.
Use the eye button to show or hide the password; Space or Enter works too. The value and selection are retained.
<div class="field">
<label class="field-label" for="group-password">Password</label>
<div class="input-group">
<input class="input-group-control" id="group-password" type="password" value="sample-password" autocomplete="new-password" aria-describedby="group-password-help">
<button class="input-group-action" data-plf-password-toggle hidden></button>
</div>
<p class="field-help" id="group-password-help">Use the eye button to show or hide the password; Space or Enter works too. The value and selection are retained.</p>
</div><div class="plf:field">
<label class="plf:field-label" for="group-password">Password</label>
<div class="plf:input-group">
<input class="plf:input-group-control" id="group-password" type="password" value="sample-password" autocomplete="new-password" aria-describedby="group-password-help">
<button class="plf:input-group-action" data-plf-password-toggle hidden></button>
</div>
<p class="plf:field-help" id="group-password-help">Use the eye button to show or hide the password; Space or Enter works too. The value and selection are retained.</p>
</div>import { Field, InputGroup, InputGroupControl, InputGroupPasswordToggle } from '@pelatform/react';
export function Example() {
return (
<Field label="Password" help="Use the eye button to show or hide the password; Space or Enter works too. The value and selection are retained.">
<InputGroup>
<InputGroupControl type="password" defaultValue="sample-password" autoComplete="new-password" />
<InputGroupPasswordToggle />
</InputGroup>
</Field>
);
}import { Field, InputGroup, InputGroupControl, InputGroupPasswordToggle } from '@pelatform/react/prefixed';
export function Example() {
return (
<Field label="Password" help="Use the eye button to show or hide the password; Space or Enter works too. The value and selection are retained.">
<InputGroup>
<InputGroupControl type="password" defaultValue="sample-password" autoComplete="new-password" />
<InputGroupPasswordToggle />
</InputGroup>
</Field>
);
}Joined addons
An affix is not part of the submitted value, so name units or protocols in the label or help text; a Combobox joins the same way with input-group-combobox.
Enter a domain and path. The application adds https://; the visual prefix is not part of this field's value.
The suffix is text, not a button. The numeric value excludes the suffix.
<div class="field">
<label class="field-label" for="group-website">Website address</label>
<div class="input-group">
<span class="input-group-text input-group-addon" aria-hidden="true">https://</span>
<input class="input-group-control" id="group-website" type="text" value="example.com" aria-describedby="group-website-help">
</div>
<p class="field-help" id="group-website-help">Enter a domain and path. The application adds https://; the visual prefix is not part of this field's value.</p>
</div>
<div class="field">
<label class="field-label" for="group-duration">Duration in minutes</label>
<div class="input-group">
<input class="input-group-control" id="group-duration" type="number" min="1" value="30" aria-describedby="group-duration-help">
<span class="input-group-text input-group-addon" aria-hidden="true">min</span>
</div>
<p class="field-help" id="group-duration-help">The suffix is text, not a button. The numeric value excludes the suffix.</p>
</div><div class="plf:field">
<label class="plf:field-label" for="group-website">Website address</label>
<div class="plf:input-group">
<span class="plf:input-group-text plf:input-group-addon" aria-hidden="true">https://</span>
<input class="plf:input-group-control" id="group-website" type="text" value="example.com" aria-describedby="group-website-help">
</div>
<p class="plf:field-help" id="group-website-help">Enter a domain and path. The application adds https://; the visual prefix is not part of this field's value.</p>
</div>
<div class="plf:field">
<label class="plf:field-label" for="group-duration">Duration in minutes</label>
<div class="plf:input-group">
<input class="plf:input-group-control" id="group-duration" type="number" min="1" value="30" aria-describedby="group-duration-help">
<span class="plf:input-group-text plf:input-group-addon" aria-hidden="true">min</span>
</div>
<p class="plf:field-help" id="group-duration-help">The suffix is text, not a button. The numeric value excludes the suffix.</p>
</div>import { Field, InputGroup, InputGroupControl, InputGroupText } from '@pelatform/react';
export function Example() {
return (
<>
<Field label="Website address" help="Enter a domain and path. The application adds https://; the visual prefix is not part of this field's value.">
<InputGroup>
<InputGroupText addon aria-hidden="true">https://</InputGroupText>
<InputGroupControl type="text" defaultValue="example.com" />
</InputGroup>
</Field>
<Field label="Duration in minutes" help="The suffix is text, not a button. The numeric value excludes the suffix.">
<InputGroup>
<InputGroupControl type="number" min={1} defaultValue={30} />
<InputGroupText addon aria-hidden="true">min</InputGroupText>
</InputGroup>
</Field>
</>
);
}import { Field, InputGroup, InputGroupControl, InputGroupText } from '@pelatform/react/prefixed';
export function Example() {
return (
<>
<Field label="Website address" help="Enter a domain and path. The application adds https://; the visual prefix is not part of this field's value.">
<InputGroup>
<InputGroupText addon aria-hidden="true">https://</InputGroupText>
<InputGroupControl type="text" defaultValue="example.com" />
</InputGroup>
</Field>
<Field label="Duration in minutes" help="The suffix is text, not a button. The numeric value excludes the suffix.">
<InputGroup>
<InputGroupControl type="number" min={1} defaultValue={30} />
<InputGroupText addon aria-hidden="true">min</InputGroupText>
</InputGroup>
</Field>
</>
);
}<form class="field">
<label class="field-label" for="group-addon-query">Report search</label>
<div class="input-group">
<span class="input-group-addon">
<span class="icon icon-search"></span>
</span>
<input class="input-group-control" id="group-addon-query" name="query" type="search" value="Reports" aria-describedby="group-addon-query-help">
<button class="input-group-action input-group-addon" type="reset" aria-label="Reset report search">
<span class="icon icon-rotate"></span>
</button>
</div>
<p class="field-help" id="group-addon-query-help">Joined icon segments share the field border. Reset restores this example's initial search value.</p>
</form><form class="plf:field">
<label class="plf:field-label" for="group-addon-query">Report search</label>
<div class="plf:input-group">
<span class="plf:input-group-addon">
<span class="plf:icon plf:icon-search"></span>
</span>
<input class="plf:input-group-control" id="group-addon-query" name="query" type="search" value="Reports" aria-describedby="group-addon-query-help">
<button class="plf:input-group-action plf:input-group-addon" type="reset" aria-label="Reset report search">
<span class="plf:icon plf:icon-rotate"></span>
</button>
</div>
<p class="plf:field-help" id="group-addon-query-help">Joined icon segments share the field border. Reset restores this example's initial search value.</p>
</form>import { Field, Icon, InputGroup, InputGroupAction, InputGroupAddon, InputGroupControl } from '@pelatform/react';
export function Example() {
return (
<form>
<Field label="Report search" help="Joined icon segments share the field border. Reset restores this example's initial search value.">
<InputGroup>
<InputGroupAddon>
<Icon name="search" />
</InputGroupAddon>
<InputGroupControl name="query" type="search" defaultValue="Reports" />
<InputGroupAction addon type="reset" aria-label="Reset report search">
<Icon name="rotate" />
</InputGroupAction>
</InputGroup>
</Field>
</form>
);
}import { Field, Icon, InputGroup, InputGroupAction, InputGroupAddon, InputGroupControl } from '@pelatform/react/prefixed';
export function Example() {
return (
<form>
<Field label="Report search" help="Joined icon segments share the field border. Reset restores this example's initial search value.">
<InputGroup>
<InputGroupAddon>
<Icon name="search" />
</InputGroupAddon>
<InputGroupControl name="query" type="search" defaultValue="Reports" />
<InputGroupAction addon type="reset" aria-label="Reset report search">
<Icon name="rotate" />
</InputGroupAction>
</InputGroup>
</Field>
</form>
);
}<div class="field">
<label class="field-label" for="input-group-small">Small</label>
<div class="input-group input-group-sm">
<input class="input-group-control" id="input-group-small" type="search" placeholder="Member name">
<span class="icon icon-search"></span>
</div>
</div>
<div class="field">
<label class="field-label" for="input-group-default">Default</label>
<div class="input-group">
<input class="input-group-control" id="input-group-default" type="search" placeholder="Member name">
<span class="icon icon-search"></span>
</div>
</div>
<div class="field">
<label class="field-label" for="input-group-large">Large</label>
<div class="input-group input-group-lg">
<input class="input-group-control" id="input-group-large" type="search" placeholder="Member name">
<span class="icon icon-search"></span>
</div>
</div><div class="plf:field">
<label class="plf:field-label" for="input-group-small">Small</label>
<div class="plf:input-group plf:input-group-sm">
<input class="plf:input-group-control" id="input-group-small" type="search" placeholder="Member name">
<span class="plf:icon plf:icon-search"></span>
</div>
</div>
<div class="plf:field">
<label class="plf:field-label" for="input-group-default">Default</label>
<div class="plf:input-group">
<input class="plf:input-group-control" id="input-group-default" type="search" placeholder="Member name">
<span class="plf:icon plf:icon-search"></span>
</div>
</div>
<div class="plf:field">
<label class="plf:field-label" for="input-group-large">Large</label>
<div class="plf:input-group plf:input-group-lg">
<input class="plf:input-group-control" id="input-group-large" type="search" placeholder="Member name">
<span class="plf:icon plf:icon-search"></span>
</div>
</div>import { Field, Icon, InputGroup, InputGroupControl } from '@pelatform/react';
export function Example() {
return (
<>
<Field label="Small">
<InputGroup size="sm">
<InputGroupControl type="search" placeholder="Member name" />
<Icon name="search" />
</InputGroup>
</Field>
<Field label="Default">
<InputGroup>
<InputGroupControl type="search" placeholder="Member name" />
<Icon name="search" />
</InputGroup>
</Field>
<Field label="Large">
<InputGroup size="lg">
<InputGroupControl type="search" placeholder="Member name" />
<Icon name="search" />
</InputGroup>
</Field>
</>
);
}import { Field, Icon, InputGroup, InputGroupControl } from '@pelatform/react/prefixed';
export function Example() {
return (
<>
<Field label="Small">
<InputGroup size="sm">
<InputGroupControl type="search" placeholder="Member name" />
<Icon name="search" />
</InputGroup>
</Field>
<Field label="Default">
<InputGroup>
<InputGroupControl type="search" placeholder="Member name" />
<Icon name="search" />
</InputGroup>
</Field>
<Field label="Large">
<InputGroup size="lg">
<InputGroupControl type="search" placeholder="Member name" />
<Icon name="search" />
</InputGroup>
</Field>
</>
);
}Error: supply a value. The complete group has an invalid border.
<div class="field">
<label class="field-label" for="group-invalid">Required group value</label>
<div class="input-group">
<input class="input-group-control" id="group-invalid" type="text" required aria-invalid="true" aria-describedby="group-invalid-error">
<span class="icon icon-search"></span>
</div>
<p class="field-error" id="group-invalid-error">Error: supply a value. The complete group has an invalid border.</p>
</div><div class="plf:field">
<label class="plf:field-label" for="group-invalid">Required group value</label>
<div class="plf:input-group">
<input class="plf:input-group-control" id="group-invalid" type="text" required aria-invalid="true" aria-describedby="group-invalid-error">
<span class="plf:icon plf:icon-search"></span>
</div>
<p class="plf:field-error" id="group-invalid-error">Error: supply a value. The complete group has an invalid border.</p>
</div>import { Field, Icon, InputGroup, InputGroupControl } from '@pelatform/react';
export function Example() {
return (
<Field label="Required group value" error="Error: supply a value. The complete group has an invalid border.">
<InputGroup>
<InputGroupControl type="text" required />
<Icon name="search" />
</InputGroup>
</Field>
);
}import { Field, Icon, InputGroup, InputGroupControl } from '@pelatform/react/prefixed';
export function Example() {
return (
<Field label="Required group value" error="Error: supply a value. The complete group has an invalid border.">
<InputGroup>
<InputGroupControl type="text" required />
<Icon name="search" />
</InputGroup>
</Field>
);
}Disabled
A disabled input mutes the whole group, but each button in it needs disabled as well.
<div class="field">
<label class="field-label" for="group-disabled">Disabled group</label>
<div class="input-group">
<input class="input-group-control" id="group-disabled" type="search" value="Unavailable" disabled>
<button class="input-group-action" type="button" aria-label="Clear unavailable field" disabled>
<span class="icon icon-x"></span>
</button>
</div>
</div><div class="plf:field">
<label class="plf:field-label" for="group-disabled">Disabled group</label>
<div class="plf:input-group">
<input class="plf:input-group-control" id="group-disabled" type="search" value="Unavailable" disabled>
<button class="plf:input-group-action" type="button" aria-label="Clear unavailable field" disabled>
<span class="plf:icon plf:icon-x"></span>
</button>
</div>
</div>import { Field, Icon, InputGroup, InputGroupAction, InputGroupControl } from '@pelatform/react';
export function Example() {
return (
<Field label="Disabled group">
<InputGroup>
<InputGroupControl type="search" defaultValue="Unavailable" disabled />
<InputGroupAction aria-label="Clear unavailable field" disabled>
<Icon name="x" />
</InputGroupAction>
</InputGroup>
</Field>
);
}import { Field, Icon, InputGroup, InputGroupAction, InputGroupControl } from '@pelatform/react/prefixed';
export function Example() {
return (
<Field label="Disabled group">
<InputGroup>
<InputGroupControl type="search" defaultValue="Unavailable" disabled />
<InputGroupAction aria-label="Clear unavailable field" disabled>
<Icon name="x" />
</InputGroupAction>
</InputGroup>
</Field>
);
}<div class="field">
<label class="field-label" for="group-readonly">Readonly group</label>
<div class="input-group">
<input class="input-group-control" id="group-readonly" type="text" value="Readable and copyable" readonly>
<span class="icon icon-search"></span>
</div>
</div><div class="plf:field">
<label class="plf:field-label" for="group-readonly">Readonly group</label>
<div class="plf:input-group">
<input class="plf:input-group-control" id="group-readonly" type="text" value="Readable and copyable" readonly>
<span class="plf:icon plf:icon-search"></span>
</div>
</div>import { Field, Icon, InputGroup, InputGroupControl } from '@pelatform/react';
export function Example() {
return (
<Field label="Readonly group">
<InputGroup>
<InputGroupControl type="text" defaultValue="Readable and copyable" readOnly />
<Icon name="search" />
</InputGroup>
</Field>
);
}import { Field, Icon, InputGroup, InputGroupControl } from '@pelatform/react/prefixed';
export function Example() {
return (
<Field label="Readonly group">
<InputGroup>
<InputGroupControl type="text" defaultValue="Readable and copyable" readOnly />
<Icon name="search" />
</InputGroup>
</Field>
);
}JavaScript
The clear button and password toggle need JavaScript, so author them hidden. The Full script (pelatform-ui.min.js) starts every component on page load, with no code of your own; with ESM imports, call init() yourself, as in Installation. For markup you add later, see Dynamic content.
<link rel="stylesheet" href="pelatform-ui.min.css">
<link rel="stylesheet" href="icons/icons.min.css">
<script src="pelatform-ui.min.js" defer></script><link rel="stylesheet" href="core/pelatform-ui-core.min.css">
<link rel="stylesheet" href="components/form.min.css">
<link rel="stylesheet" href="icons/icons.min.css">
<script src="core/pelatform-ui-core.min.js" defer></script>
<script src="components/input-group.min.js" defer></script>
<script>document.addEventListener('DOMContentLoaded', () => PLF.init());</script><link rel="stylesheet" href="pelatform-ui.prefixed.min.css">
<link rel="stylesheet" href="icons/icons.prefixed.min.css">
<script src="pelatform-ui.min.js" defer></script><link rel="stylesheet" href="core/pelatform-ui-core.prefixed.min.css">
<link rel="stylesheet" href="components/form.prefixed.min.css">
<link rel="stylesheet" href="icons/icons.prefixed.min.css">
<script src="core/pelatform-ui-core.min.js" defer></script>
<script src="components/input-group.min.js" defer></script>
<script>document.addEventListener('DOMContentLoaded', () => PLF.init());</script>| Attribute | Purpose |
|---|---|
data-plf-clear |
On an input-group-action button beside the group’s one <input>: shows while the field holds a value and is editable, then empties it, sends an input event and focuses the field. Named Clear unless it has a name |
data-plf-password-toggle |
On an input-group-action button beside an <input type="password">: shows or hides the password, keeps the selection and sets aria-pressed. Named Show password unless it has a name |
| Method | Behavior |
|---|---|
PLF. |
Returns the button’s instance, creating it for valid markup |
PLF. |
Returns the instance or null |
instance. |
Removes listeners and what the script added, so the button is hidden again; the field keeps its value |
After setting the field’s value in code, dispatch an input event so the clear button follows.
React
InputGroup from @pelatform/react renders the group around its parts, in which an Icon needs no class; InputGroupClear and InputGroupPasswordToggle do what the two hooks do.
| Prop | Values | Default |
|---|---|---|
size |
sm, lg |
The default size |
customClear |
true hides the browser’s own clear button on a search input |
false |
addon |
On InputGroupText and InputGroupAction, true joins the part as a muted segment |
false |
aria-label |
On InputGroupClear and InputGroupPasswordToggle, the button’s name |
Clear, Show password |
The parts:
| Part | Element |
|---|---|
InputGroupControl |
An input with input-group-control, a direct child of InputGroup, which takes its Field’s label, help and error |
InputGroupText |
A span with input-group-text |
InputGroupAddon |
A span with input-group-addon |
InputGroupAction |
A button with input-group-action, type="button" unless given another type |
InputGroupClear |
An InputGroupAction hidden while the control is empty, disabled or read-only; a click empties the control with an input event, so its onChange follows, and focuses it |
InputGroupPasswordToggle |
An InputGroupAction with aria-pressed, which shows or hides the password and keeps the selection |
Other props are the element’s own, className and ref included.
CSS variables
Input Group shares the Input variables; override them on a root or on a single group.
| Variable | Default |
|---|---|
--plf-input-height |
Minimum height: 2. (36px); 2rem (32px) with input-group-sm, 2. (40px) with input-group-lg |
--plf-input-bg, --plf-input-color |
--plf-color-field, --plf-color-text |
--plf-input-border |
--plf-color-input |
--plf-input-hover-border |
--plf-input-border, otherwise --plf-color-border |
--plf-input-invalid-border |
--plf-color-danger |
--plf-input-radius |
--plf-radius-lg, 0. (8px) |
--plf-input-shadow |
--plf-shadow-xs |
--plf-input-focus-width, --plf-input-focus-color |
--plf-focus-width (2px), --plf-focus-color, around the whole group |
--plf-input-focus-offset |
0px, so the ring sits just outside the border |
--plf-input-group-icon-size |
--plf-control-icon-size (16px); 14px with input-group-sm, 18px with input-group-lg |
--plf-input-group-icon-color |
--plf-color-text-muted; addon icons take the addon color |
--plf-input-addon-bg |
--plf-color-surface-raised |
--plf-input-addon-color |
--plf-color-text-muted |
--plf-input-addon-border |
--plf-input-border, the segment divider, so it matches the group’s border |
--plf-input-addon-hover-bg |
--plf-color-surface-muted, on addon buttons |