Logo

Input

Native text input primitives with labeling and feedback patterns.

Preview

Beta

We will send release updates to this address.

https://

Use input groups when text or icons clarify the expected format.

Usage

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>

Examples

Basic field

Use the field helpers when an input needs a label, supporting text, and optional badges around the native control.

Beta

We will send release updates to this address.

Invalid with reactive forms

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.

Input groups

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.

https://

Text addons are useful when part of the value is fixed or implied.

Readonly and disabled

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.

Custom Styling

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.

Team

This preview applies local radius, focus, badge, and addon token overrides.

Token Inspector

Hover the field shell, label, badge, group surface, addon, description, or error text to inspect how the input primitives distribute spacing and state styling.

Live
https://

Inspect the field shell, badge, addon surface, input control, description, and validation text.

A public URL is required.

Design Tokens

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;