codefast/ui

Command Palette

Search for a command to run...

Source
Form

Input

Text input with focus ring, disabled state, and file input styling.

Examples

File input

type="file" is styled to match the rest of the form controls.

Select a picture to upload.

12 lines
import { Field, FieldDescription, FieldLabel } from "@codefast/ui/field";
import { Input } from "@codefast/ui/input";

export function InputFile() {
  return (
    <Field>
      <FieldLabel htmlFor="picture">Picture</FieldLabel>
      <Input id="picture" type="file" />
      <FieldDescription>Select a picture to upload.</FieldDescription>
    </Field>
  );
}

Badge

Use Badge in the label to highlight a recommended field.

17 lines
import { Badge } from "@codefast/ui/badge";
import { Field, FieldLabel } from "@codefast/ui/field";
import { Input } from "@codefast/ui/input";

export function InputBadge() {
  return (
    <Field>
      <FieldLabel htmlFor="input-badge">
        Webhook URL{" "}
        <Badge variant="secondary" className="ms-auto">
          Beta
        </Badge>
      </FieldLabel>
      <Input id="input-badge" type="url" placeholder="https://api.example.com/webhook" />
    </Field>
  );
}

Basic

A text input component for forms and user data entry with built-in styling and accessibility features.

5 lines
import { Input } from "@codefast/ui/input";

export function InputBasic() {
  return <Input placeholder="Enter text" />;
}

Button Group

To add buttons to an input, use the ButtonGroup component. See the Button Group component for more examples.

16 lines
import { Button } from "@codefast/ui/button";
import { ButtonGroup } from "@codefast/ui/button-group";
import { Field, FieldLabel } from "@codefast/ui/field";
import { Input } from "@codefast/ui/input";

export function InputButtonGroup() {
  return (
    <Field>
      <FieldLabel htmlFor="input-button-group">Search</FieldLabel>
      <ButtonGroup>
        <Input id="input-button-group" placeholder="Type to search..." />
        <Button variant="outline">Search</Button>
      </ButtonGroup>
    </Field>
  );
}

Disabled

Use the disabled prop to disable the input. To style the disabled state, add the data-disabled attribute to the Field component.

This field is currently disabled.

12 lines
import { Field, FieldDescription, FieldLabel } from "@codefast/ui/field";
import { Input } from "@codefast/ui/input";

export function InputDisabled() {
  return (
    <Field data-disabled>
      <FieldLabel htmlFor="input-demo-disabled">Email</FieldLabel>
      <Input id="input-demo-disabled" type="email" placeholder="Email" disabled />
      <FieldDescription>This field is currently disabled.</FieldDescription>
    </Field>
  );
}

Field

Use Field, FieldLabel, and FieldDescription to create an input with a label and description.

Choose a unique username for your account.

12 lines
import { Field, FieldDescription, FieldLabel } from "@codefast/ui/field";
import { Input } from "@codefast/ui/input";

export function InputField() {
  return (
    <Field>
      <FieldLabel htmlFor="input-field-username">Username</FieldLabel>
      <Input id="input-field-username" type="text" placeholder="Enter your username" />
      <FieldDescription>Choose a unique username for your account.</FieldDescription>
    </Field>
  );
}

Field Group

Use FieldGroup to show multiple Field blocks and to build forms.

We'll send updates to this address.

25 lines
import { Button } from "@codefast/ui/button";
import { Field, FieldDescription, FieldGroup, FieldLabel } from "@codefast/ui/field";
import { Input } from "@codefast/ui/input";

export function InputFieldgroup() {
  return (
    <FieldGroup>
      <Field>
        <FieldLabel htmlFor="fieldgroup-name">Name</FieldLabel>
        <Input id="fieldgroup-name" placeholder="Jordan Lee" />
      </Field>
      <Field>
        <FieldLabel htmlFor="fieldgroup-email">Email</FieldLabel>
        <Input id="fieldgroup-email" type="email" placeholder="name@example.com" />
        <FieldDescription>We&apos;ll send updates to this address.</FieldDescription>
      </Field>
      <Field orientation="horizontal">
        <Button type="reset" variant="outline">
          Reset
        </Button>
        <Button type="submit">Submit</Button>
      </Field>
    </FieldGroup>
  );
}

Form

A full form example with multiple inputs, a select, and a button.

We'll never share your email with anyone.

51 lines
import { Button } from "@codefast/ui/button";
import { Field, FieldDescription, FieldGroup, FieldLabel } from "@codefast/ui/field";
import { Input } from "@codefast/ui/input";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@codefast/ui/select";

export function InputForm() {
  return (
    <form className="w-full max-w-sm">
      <FieldGroup>
        <Field>
          <FieldLabel htmlFor="form-name">Name</FieldLabel>
          <Input id="form-name" type="text" placeholder="Ava Stone" required />
        </Field>
        <Field>
          <FieldLabel htmlFor="form-email">Email</FieldLabel>
          <Input id="form-email" type="email" placeholder="john@example.com" />
          <FieldDescription>We&apos;ll never share your email with anyone.</FieldDescription>
        </Field>
        <div className="grid grid-cols-2 gap-4">
          <Field>
            <FieldLabel htmlFor="form-phone">Phone</FieldLabel>
            <Input id="form-phone" type="tel" placeholder="+1 (555) 123-4567" />
          </Field>
          <Field>
            <FieldLabel htmlFor="form-country">Country</FieldLabel>
            <Select defaultValue="us">
              <SelectTrigger id="form-country">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="us">United States</SelectItem>
                <SelectItem value="uk">United Kingdom</SelectItem>
                <SelectItem value="ca">Canada</SelectItem>
              </SelectContent>
            </Select>
          </Field>
        </div>
        <Field>
          <FieldLabel htmlFor="form-address">Address</FieldLabel>
          <Input id="form-address" type="text" placeholder="123 Main St" />
        </Field>
        <Field orientation="horizontal">
          <Button type="button" variant="outline">
            Cancel
          </Button>
          <Button type="submit">Submit</Button>
        </Field>
      </FieldGroup>
    </form>
  );
}

Grid

Use a grid layout to place multiple inputs side by side.

17 lines
import { Field, FieldGroup, FieldLabel } from "@codefast/ui/field";
import { Input } from "@codefast/ui/input";

export function InputGrid() {
  return (
    <FieldGroup className="grid max-w-sm grid-cols-2">
      <Field>
        <FieldLabel htmlFor="first-name">First Name</FieldLabel>
        <Input id="first-name" placeholder="Jordan" />
      </Field>
      <Field>
        <FieldLabel htmlFor="last-name">Last Name</FieldLabel>
        <Input id="last-name" placeholder="Lee" />
      </Field>
    </FieldGroup>
  );
}

Inline

Use Field with orientation='horizontal' to create an inline input. Pair with Button to create a search input with a button.

12 lines
import { Button } from "@codefast/ui/button";
import { Field } from "@codefast/ui/field";
import { Input } from "@codefast/ui/input";

export function InputInline() {
  return (
    <Field orientation="horizontal">
      <Input type="search" placeholder="Search..." />
      <Button>Search</Button>
    </Field>
  );
}

Input Group

To add icons, text, or buttons inside an input, use the InputGroup component. See the Input Group component for more examples.

https://
20 lines
import { Field, FieldLabel } from "@codefast/ui/field";
import { InputGroup, InputGroupAddon, InputGroupInput, InputGroupText } from "@codefast/ui/input-group";
import { InfoIcon } from "lucide-react";

export function InputInputGroup() {
  return (
    <Field>
      <FieldLabel htmlFor="input-group-url">Website URL</FieldLabel>
      <InputGroup>
        <InputGroupInput id="input-group-url" placeholder="example.com" />
        <InputGroupAddon>
          <InputGroupText>https://</InputGroupText>
        </InputGroupAddon>
        <InputGroupAddon align="inline-end">
          <InfoIcon />
        </InputGroupAddon>
      </InputGroup>
    </Field>
  );
}

Invalid

Use the aria-invalid prop to mark the input as invalid. To style the invalid state, add the data-invalid attribute to the Field component.

This field contains validation errors.

12 lines
import { Field, FieldDescription, FieldLabel } from "@codefast/ui/field";
import { Input } from "@codefast/ui/input";

export function InputInvalid() {
  return (
    <Field data-invalid>
      <FieldLabel htmlFor="input-invalid">Invalid Input</FieldLabel>
      <Input id="input-invalid" placeholder="Error" aria-invalid />
      <FieldDescription>This field contains validation errors.</FieldDescription>
    </Field>
  );
}

Required

Use the required attribute to indicate required inputs.

This field must be filled out.

14 lines
import { Field, FieldDescription, FieldLabel } from "@codefast/ui/field";
import { Input } from "@codefast/ui/input";

export function InputRequired() {
  return (
    <Field>
      <FieldLabel htmlFor="input-required">
        Required Field <span className="text-destructive">*</span>
      </FieldLabel>
      <Input id="input-required" placeholder="This field is required" required />
      <FieldDescription>This field must be filled out.</FieldDescription>
    </Field>
  );
}

RTL

Right-to-left layout support for languages such as Arabic and Hebrew.

Translations are AI-generated for demonstration and may be imperfect.

مفتاح API الخاص بك مشفر ومخزن بأمان.

44 lines
import { Field, FieldDescription, FieldLabel } from "@codefast/ui/field";
import { Input } from "@codefast/ui/input";

import type { Translations } from "#/features/components-catalog/components/detail/language";
import { useTranslation } from "#/features/components-catalog/components/detail/language-context";

const translations: Translations = {
  en: {
    dir: "ltr",
    values: {
      apiKey: "API Key",
      placeholder: "sk-...",
      description: "Your API key is encrypted and stored securely.",
    },
  },
  ar: {
    dir: "rtl",
    values: {
      apiKey: "مفتاح API",
      placeholder: "sk-...",
      description: "مفتاح API الخاص بك مشفر ومخزن بأمان.",
    },
  },
  he: {
    dir: "rtl",
    values: {
      apiKey: "מפתח API",
      placeholder: "sk-...",
      description: "מפתח ה-API שלך מוצפן ונשמר בצורה מאובטחת.",
    },
  },
};

export function InputRtl() {
  const { dir, t } = useTranslation(translations, "ar");

  return (
    <Field dir={dir}>
      <FieldLabel htmlFor="input-rtl-api-key">{t.apiKey}</FieldLabel>
      <Input id="input-rtl-api-key" type="password" placeholder={t.placeholder} dir={dir} />
      <FieldDescription>{t.description}</FieldDescription>
    </Field>
  );
}

Anatomy

How the parts nest — every slot the component exposes, in composition order.

Input

Features

  • Forwards every native <input> prop and type (text, email, password, number, …), with type="file" getting dedicated styling.
  • Built-in invalid (aria-invalid) and disabled states, styled without extra classes.
  • Composes with Field/FieldGroup for a labelled field, InputGroup for icons or buttons inside the field, and ButtonGroup for adjacent action buttons.

API reference

Props for each part of the component. All native element props are also forwarded.

Input

Renders a native <input>; forwards every native input prop.

type"text" | "email" | "password" | "file" | "number" | …

Native input type. file gets dedicated styling.

Default"text"

disabledboolean

Dims the field and blocks interaction.

Defaultfalse

aria-invalidboolean

Switches the field to the destructive error ring.

Defaultfalse

Accessibility

Built to be keyboard-navigable and screen-reader friendly out of the box.

KeyFunction
TabMoves focus to and from the input.
  • Always associate a Label via htmlFor / id so the field has an accessible name.
  • Use aria-invalid plus a visible error message — colour alone is not sufficient.
  • Describe the field with aria-describedby when you show helper or error text.

Guidelines

Conventions that keep usage consistent across an app.

Do

  • Give every input a visible label.
  • Use the correct type so mobile keyboards and autofill behave well.

Don’t

  • Don’t use placeholder text as a replacement for a label.
  • Don’t disable a field when a read-only state would communicate intent better.

Explore further

Ready to integrate?

Follow the Getting Started guide to install @codefast/ui, or browse the full component gallery.