input

Input

Text input with label, states, and helpers.

Input Examples

Copy-ready examples for a floating-label input with variants, icon slot, and support text.

Basic usage

A simple controlled input using `value` + `onChange`.

If you pass `value`, treat the component as controlled (always update it in `onChange`).

If you don't pass `value`, the browser manages the value (uncontrolled).

Live preview

Controlled input

"use client";

import { useState } from "react";
import Input from "@/_components/forms/input/Input";

export default function Example() {
  const [value, setValue] = useState(""); // controlled state

  return (
    <Input
      name="email"
      label="Email"
      type="email"
      value={value}
      onChange={(e) => setValue((e.target as HTMLInputElement).value)}
      placeholder="you@example.com"
    />
  );
}

Variants

Switch between outlined (default) and filled.

Live preview

Outlined (default)
Filled

Outlined vs filled

"use client";

import { useState } from "react";
import Input from "@/_components/forms/input/Input";

export default function Example() {
  const [value, setValue] = useState("Hello");

  return (
    <div style={{ display: "flex", gap: 12, flexWrap: "wrap" }}>
      <Input
        name="outlined"
        label="Title"
        value={value}
        onChange={(e) => setValue((e.target as HTMLInputElement).value)}
      />

      <Input
        name="filled"
        label="Title"
        variant="filled"
        value={value}
        onChange={(e) => setValue((e.target as HTMLInputElement).value)}
      />
    </div>
  );
}

With leading icon

Use `iconContent` to render a leading icon/content inside the field.

Any ReactNode works for `iconContent` (an icon, badge, loader, etc.).

Live preview

Search

Search input with icon

"use client";

import { useState, useId } from "react";
import Input from "@/_components/forms/input/Input";
import Icon from "@/_components/icon/Icon";

export default function Example() {
  const id = useId();
  const [q, setQ] = useState("");

  return (
    <Input
      name={`${id}-search`}
      label="Search"
      type="search"
      iconContent={<Icon name="Search" size="small" />}
      value={q}
      onChange={(e) => setQ((e.target as HTMLInputElement).value)}
      placeholder="Search..." 
    />
  );
}

Support text states

Show helper text under the input, with optional styling state.

`extraTextState` only affects the support text styling (it doesn't validate the input by itself).

Use it alongside your form validation logic (e.g., show error only after blur/submit).

Live preview

Shown as support text

Looks good

Minimum 8 characters

Support / success / error

import Input from "@/_components/forms/input/Input";

export default function Example() {
  return (
    <div style={{ display: "grid", gap: 14 }}>
      <Input
        name="support"
        label="Project"
        value="cssnt_components"
        extraText="Shown as support text"
        extraTextState="support"
      />

      <Input
        name="success"
        label="Username"
        value="luischvz"
        editState="readonly"
        extraText="Looks good"
        extraTextState="success"
      />

      <Input
        name="error"
        label="Password"
        type="password"
        required
        extraText="Minimum 8 characters"
        extraTextState="error"
      />
    </div>
  );
}

Edit state

Disable editing with `editState`.

`editState="readonly"` sets the native `readOnly` attribute.

`editState="disabled"` sets the native `disabled` attribute.

Live preview

Free
Readonly
Disabled

free / readonly / disabled

import Input from "@/_components/forms/input/Input";

export default function Example() {
  return (
    <div style={{ display: "flex", gap: 12, flexWrap: "wrap" }}>
      <Input name="free" label="Name" placeholder="John" />

      <Input
        name="readonly"
        label="Readonly"
        editState="readonly"
        value="Locked"
      />

      <Input name="disabled" label="Disabled" editState="disabled" />
    </div>
  );
}

Common input types

Use native HTML input types (email, tel, date, number, etc.).

Live preview

Tip: keep it controlled to normalize empty string.

Types overview

"use client";

import { useId, useState } from "react";
import Input from "@/_components/forms/input/Input";

export default function Example() {
  const id = useId();
  const [amount, setAmount] = useState<number | "">("");

  return (
    <div style={{ display: "grid", gap: 14 }}>
      <div style={{ display: "flex", gap: 12, flexWrap: "wrap" }}>
        <Input name={`${id}-text`} label="Text" placeholder="Type here" />
        <Input name={`${id}-tel`} label="Phone" type="tel" placeholder="+52 55 ..." />
      </div>

      <div style={{ display: "flex", gap: 12, flexWrap: "wrap" }}>
        <Input name={`${id}-url`} label="Website" type="url" placeholder="https://example.com" />
        <Input name={`${id}-date`} label="Date" type="date" />
      </div>

      <Input
        name={`${id}-number`}
        label="Amount"
        type="number"
        value={amount}
        onChange={(e) => {
          const next = (e.target as HTMLInputElement).value;
          setAmount(next === """ ? """ : Number(next));
        }}
        placeholder="0"
        extraText="Tip: keep it controlled to normalize empty string."
        extraTextState="support"
      />
    </div>
  );
}

On this page

Input Props

Input — Props
PropTypeRequiredDefaultDescription
namestringNoUsed for `id`, `name`, and `htmlFor`. Should be unique per field.
labelstringNoFloating label content.
type"text" | "password" | "email" | "number" | "search" | "tel" | "url" | "date" | "time" | "datetime-local" | "month" | "week"No"text"Native input type.
placeholderstringNo" "Placeholder. Defaults to a single space so the floating label logic works reliably.
valuestring | numberNoInput value. If you pass this, treat the input as controlled.
onChange(...args: unknown[]) => unknownNoChange handler forwarded to `<input onChange>`.
variant"filled" | "outlined"No"outlined"Visual variant.
iconContentstring | ReactNodeNoOptional leading icon/content rendered before the input.
requiredbooleanNofalseSets `required` on the input and adds a required label class (asterisk via CSS).
editState"disabled" | "readonly" | "free"No"free"Sets `disabled` or `readOnly` on the input and adds root state classes.
extraTextstringNoOptional support text rendered under the input.
extraTextState"error" | "success" | "support"NoSupport text style class applied to the `<p>` node.