Input
The control you reach for whenever the value is typed rather than chosen. It is
a real <input>, so type, placeholder, required, pattern, minLength
and the rest work exactly as they do on the platform — what the library adds is
the design system's metrics, the two-tone focus ring, and the wiring that makes
it participate in a Field without a line of glue.
Lowercase letters, numbers and dashes.
Base UI's Input is Field.Control under a friendlier name. That is why
there is no Field.Control in this library and no <Field.Control render={...}>
dance: <Input> inside a <Field.Root> already picks up the label, the
description, the error message, the name used on submit, and the validity
attributes.
Import
import { Input } from "@forte-ui/react";Examples
Sizes
size moves height, inline padding and font size together, and the numbers come
from the same --forte-control-* tokens Select.Trigger reads — so an input and
a select on one row are the same height at every data-forte-density setting.
Variants
variant changes only how much weight the control carries: outline reads as
a form control, soft as a filled field, ghost as an inline affordance —
the same three the select trigger has.
States
Disabled and read-only are not the same thing and do not look the same.
Disabled drops to 55% opacity and takes cursor: not-allowed. Read-only keeps
full contrast, a panel-coloured background, and the text cursor — everywhere
else in this library a read-only control falls back to the default arrow, but
selecting and copying the value is the point of the state, so the text cursor
stays.
Multi-line
Use Textarea. It is the same Field.Control rendered
as a <textarea>, wearing the same variants, sizes and colour slots, and it
adds the things a paragraph needs that a control height cannot express — a
height counted in rows, a growth ceiling, and autoResize.
Accessibility
An input needs an accessible name, and <Field.Label> is the way to give it
one — it renders a real <label> wired with htmlFor, so clicking the text
focuses the control and the hit target grows by the width of the label. Where
the design has no visible label, aria-label on the input is the fallback.
Placeholder text is coloured --forte-color-foreground-muted (5.82:1) rather
than --forte-color-foreground-subtle (3.73:1). SC 1.4.3 has no exemption for
placeholders in an enabled control, and Firefox's own 0.54 ::placeholder
opacity is reset for the same reason.
In forced-colors mode the control paints Field / FieldText with a
FieldText boundary. That last part matters for soft and ghost, whose
border is transparent — a value forced-colors replaces with a system colour
of its choosing rather than leaving invisible, so without the restatement the
three variants would stop looking like the same control.
Theming
Every --forte-input-* property is declared on the input element itself, and an
element's own declaration beats an inherited one — so setting these on :root,
on a theme scope or on any ancestor does nothing. Set them on the input, through
className (an unlayered rule beats @layer forte.components whatever its
specificity) or an inline style.
The global tokens they resolve to — --forte-color-*, --forte-control-*,
--forte-radius-* — are the exception: this component only reads those, so
re-pointing them from :root or a theme scope moves every input at once.
| Property | Controls | Default |
|---|---|---|
--forte-input-height | Control height (reset per size) | var(--forte-control-h-md) |
--forte-input-padding-x | Inline padding (reset per size) | var(--forte-control-px-md) |
--forte-input-font-size | Font size (reset per size) | var(--forte-font-size-2) |
--forte-input-radius | Corner radius | var(--forte-radius-control) |
--forte-input-border-width | Border width | 1px |
--forte-input-bg | Background (reset per variant) | var(--forte-color-background) |
--forte-input-bg-hover | Background on hover | var(--forte-color-panel-hover) |
--forte-input-fg | Text colour | var(--forte-color-foreground) |
--forte-input-placeholder-fg | Placeholder colour | var(--forte-color-foreground-muted) |
--forte-input-border-color | Border colour (reset per variant, and by data-invalid) | var(--forte-color-border) |
--forte-input-border-color-hover | Border colour on hover | var(--forte-color-border-strong) |
--forte-input-caret-color | Caret colour | var(--forte-color-primary) |
--forte-input-selection-bg | Selection background | var(--forte-color-primary-soft) |
--forte-input-selection-fg | Selection text colour | var(--forte-color-primary-text) |
API reference
Input
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | Additional class name(s). Applied after the internal styles so consumer utilities (e.g. Tailwind) win without needing `!important`. | |
fullWidth | boolean | false | Stretch the input to fill the width of its container. Only needed outside a `Field.Root` — a field is a flex column, so an input inside one already stretches. |
size | InputSize | md | Size of the control. Height, inline padding and font size all move together, and the actual numbers follow the ambient `data-forte-density` setting. Matches `Select.Trigger`'s scale, so an input and a select on the same row line up. This shadows the native `size` attribute (which sets a width in characters). Reach for `fullWidth`, a CSS `inline-size`, or `render={<input size={10} />}` if you need that instead. |
variant | InputVariant | outline | How much visual weight the control carries. `outline` reads as a form control, `soft` as a filled field, `ghost` as an inline affordance. |
Everything else is a native <input> prop and passes straight through, plus
Base UI's render, onValueChange and defaultValue.