Anatomy
Click any field to see focus lift
States
All input states
Do / Don't
✓ Do
Always pair an input with a visible label and hint. Don't rely on placeholder as the label.
✕ Don't
Don't override border-radius or thin the border. SLAB inputs are chunky and square — that's the system.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| label | string | null | Mono uppercase label rendered above the field. |
| hint | string | null | Helper text below. Turns coral when invalid=true. |
| prefix | ReactNode | null | Content in a bordered left-attached cell (e.g. "$", "https://"). |
| suffix | ReactNode | null | Content in a bordered right-attached cell (e.g. "kg", "%", "USD"). |
| invalid | boolean | false | Switches border and hint text to coral error color. |
| style | CSSProperties | {} | Applied to the outer wrapper — use for width, margin. |
| inputStyle | CSSProperties | {} | Applied to the inner <input> element only. |
| ...rest | InputHTMLAttributes | — | All native input props: type, placeholder, value, onChange, disabled, etc. |
Usage
import { Input } from "components/forms/Input";
// Basic
<Input label="Campaign name" placeholder="e.g. Summer Sale" />
// With prefix + hint
<Input
label="Website"
prefix="https://"
hint="Your public campaign URL"
placeholder="yourdomain.com"
/>
// With suffix
<Input
label="Weight"
suffix="kg"
type="number"
placeholder="0"
/>
// Prefix + suffix
<Input
label="Price"
prefix="$"
suffix="USD"
type="number"
/>
// Validation state
<Input
label="Email"
type="email"
invalid={!isValidEmail}
hint={!isValidEmail ? "Enter a valid email." : ""}
value={email}
onChange={e => setEmail(e.target.value)}
/>