Basic field
Use the field helpers when an input needs a label, supporting text, and optional badges around the native control.
We will send release updates to this address.
Icons by @ng-icons/tabler-icons
The component library does not provide icons.
Native text input primitives with labeling and feedback patterns.
Preview
We will send release updates to this address.
Use input groups when text or icons clarify the expected format.
TS
import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { FrInputModule } from '@frame-ui-ng/components/input';
emailControl = new FormControl('team@northwind.dev');HTML
<div frInputField>
<div frInputHeader>
<label frInputLabel for="email">Email</label>
<span frInputBadge>Beta</span>
</div>
<div frInputControl>
<input frInput id="email" type="email" [formControl]="emailControl" />
</div>
<p frInputDescription>We will send release updates to this address.</p>
</div>Use the field helpers when an input needs a label, supporting text, and optional badges around the native control.
We will send release updates to this address.
Reactive forms can drive the invalid state directly, so the control styling and helper message stay in sync with Angular validation.
Delete the value to see the reactive validation state.
Use input groups when text or icons should sit directly inside the same interactive shell as the input itself.
Inline addons keep search, URL, and token inputs compact.
Text addons are useful when part of the value is fixed or implied.
Readonly and disabled states stay within the same primitive API, which keeps form structure stable even when behavior changes.
Readonly inputs keep the same structure while signaling that the value cannot be changed here.
Disabled inputs inherit the primitive opacity treatment and block interaction.
Override input tokens on a local wrapper when a form section needs a different radius, focus ring, badge treatment, or addon surface without changing the primitive structure.
This preview applies local radius, focus, badge, and addon token overrides.
Hover the field shell, label, badge, group surface, addon, description, or error text to inspect how the input primitives distribute spacing and state styling.
Inspect the field shell, badge, addon surface, input control, description, and validation text.
A public URL is required.
Use these CSS custom properties to tune input spacing, label and helper typography, root control states, grouped addons, and badges without changing the primitive structure.
SCSS
--frame-input-field-gap: 0.5rem;
--frame-input-header-gap: 0.75rem;
--frame-input-field-group-gap: 1rem;
--frame-input-label-font-size: 0.875rem;
--frame-input-label-font-weight: 600;
--frame-input-description-color: var(--frame-muted-foreground);
--frame-input-description-font-size: 0.8125rem;
--frame-input-error-color: var(--frame-destructive);
--frame-input-error-font-size: 0.8125rem;
--frame-input-root-height: 2.5rem;
--frame-input-root-radius: var(--frame-radius-md);
--frame-input-root-bg: var(--frame-surface);
--frame-input-root-color: var(--frame-surface-foreground);
--frame-input-root-border: var(--frame-border);
--frame-input-root-font-size: 0.875rem;
--frame-input-root-padding-inline: 0.875rem;
--frame-input-root-placeholder-color: var(--frame-muted-foreground);
--frame-input-root-hover-border: color-mix(in srgb, var(--frame-border) 80%, var(--frame-foreground));
--frame-input-root-focus-border: color-mix(in srgb, var(--frame-ring) 70%, var(--frame-border));
--frame-input-root-focus-shadow: 0 0 0 3px color-mix(in srgb, var(--frame-ring) 22%, transparent);
--frame-input-root-invalid-border: color-mix(in srgb, var(--frame-destructive) 65%, var(--frame-border));
--frame-input-root-invalid-shadow: 0 0 0 3px color-mix(in srgb, var(--frame-destructive) 14%, transparent);
--frame-input-root-disabled-opacity: 0.55;
--frame-input-root-readonly-bg: color-mix(in srgb, var(--frame-surface) 80%, var(--frame-muted));
--frame-input-root-transition-duration: 150ms;
--frame-input-file-padding-block: 0.375rem;
--frame-input-file-button-radius: calc(var(--frame-radius-md) - 2px);
--frame-input-file-button-bg: color-mix(in srgb, var(--frame-surface) 80%, var(--frame-muted));
--frame-input-file-button-hover-bg: color-mix(in srgb, var(--frame-surface) 65%, var(--frame-muted));
--frame-input-file-button-font-size: 0.8125rem;
--frame-input-file-button-font-weight: 600;
--frame-input-file-button-margin-inline-end: 0.75rem;
--frame-input-file-button-padding: 0.45rem 0.75rem;
--frame-input-file-button-transition-duration: var(--frame-input-root-transition-duration);
--frame-input-badge-height: 1.5rem;
--frame-input-badge-padding-inline: 0.5rem;
--frame-input-badge-radius: 999px;
--frame-input-badge-border: color-mix(in srgb, var(--frame-primary) 24%, transparent);
--frame-input-badge-bg: color-mix(in srgb, var(--frame-primary) 12%, transparent);
--frame-input-badge-color: var(--frame-primary);
--frame-input-badge-font-size: 0.6875rem;
--frame-input-badge-font-weight: 700;
--frame-input-group-height: var(--frame-input-root-height);
--frame-input-group-radius: var(--frame-input-root-radius);
--frame-input-group-bg: var(--frame-input-root-bg);
--frame-input-group-border: var(--frame-input-root-border);
--frame-input-group-focus-border: var(--frame-input-root-focus-border);
--frame-input-group-focus-shadow: var(--frame-input-root-focus-shadow);
--frame-input-group-transition-duration: var(--frame-input-root-transition-duration);
--frame-input-group-input-padding-inline: var(--frame-input-root-padding-inline);
--frame-input-group-addon-min-width: 2.5rem;
--frame-input-group-addon-bg: color-mix(in srgb, var(--frame-surface) 80%, var(--frame-muted));
--frame-input-group-addon-color: var(--frame-muted-foreground);
--frame-input-group-addon-padding-inline: 0.75rem;
--frame-input-group-addon-border: var(--frame-border);
--frame-input-group-text-font-size: 0.8125rem;
--frame-input-group-text-font-weight: 600;