Input

Text-like native inputs: text, email, search, tel, url, and similar. Labels and messages belong to Field. For several lines, use TextArea; for passwords, Password input.

Installation

bun add @harmo-ui/css @harmo-ui/react

Usage

import { Field, Input } from "@harmo-ui/react";

<Field label="Billing email" error="Enter a valid email address.">
  <Input name="billing-email" type="email" autoComplete="email" />
</Field>

Examples

This site is using your theme

Default

34px tall and as wide as its container. The placeholder is gray; give the input a label in a Field rather than relying on it.

<>
  <Field label="Company">
    <Input
      name="company"
      type="text"
      autoComplete="organization"
      placeholder="Acme Inc."
    />
  </Field>
  <Field label="Full name">
    <Input
      name="full-name"
      type="text"
      autoComplete="name"
      defaultValue="Jane Smith"
    />
  </Field>
</>

Types

Any text-like type works, and the browser brings its keyboard and autofill. Give each an autocomplete value where one fits.

<>
  <Field label="Work email">
    <Input name="work-email" type="email" autoComplete="email" />
  </Field>
  <Field label="Phone number">
    <Input name="phone" type="tel" autoComplete="tel" />
  </Field>
  <Field label="Website">
    <Input
      name="website"
      type="url"
      autoComplete="url"
      placeholder="https://"
    />
  </Field>
  <Field label="Search contacts">
    <Input name="contact-search" type="search" />
  </Field>
</>

Invalid

aria-invalid="true" turns the border red, with a red ring when focused. Set it only after the app has validated the value.

Enter a valid email address.

<Field label="Billing email" error="Enter a valid email address.">
  <Input
    name="billing-email"
    type="email"
    autoComplete="email"
    defaultValue="not-an-email"
  />
</Field>

Read-only and disabled

Both get a gray background. A readonly input can still be focused and copied from; a disabled one can't, and its text fades.

<>
  <Field label="Account ID">
    <Input name="account-id" type="text" defaultValue="ACC-20391" readOnly />
  </Field>
  <Field label="Sender name">
    <Input
      name="sender-name"
      type="text"
      defaultValue="Acme Support"
      disabled
    />
  </Field>
  <Field label="Sender ID">
    <Input
      name="sender-id"
      type="text"
      placeholder="Not available in your region"
      disabled
    />
  </Field>
</>

Next to a button

In a flex row, the input takes the room the button leaves. The row here is a plain flex container of your own.

<div style={{ display: "flex", gap: 8 }}>
  <Input
    type="search"
    aria-label="Search conversations"
    placeholder="Search conversations"
  />
  <Button variant="secondary">Search</Button>
</div>

API reference

React

<Input> renders the <input>. In a Field, it takes the field's id and descriptions. Its props are the input's attributes.

HTML

An <input class="hinput" type="…"> with a text-like type, named by a <label for> matching its id, or by aria-label. Load input.css; field.css for a label and messages. It needs no script.

HookEffect
placeholderShown in --harmo-color-text-tertiary
aria-invalid="true"--harmo-color-danger border, and a red ring when focused
readonlySecondary background; still focusable and copyable
disabledSecondary background, no shadow, and --harmo-color-text-tertiary text

See Input's full contract.

Accessibility

  • Name it with a <label for> in a Field, and connect a description and error with aria-describedby.
  • Set aria-invalid="true" only after the application has validated the value, and give fields an autocomplete value where one fits.
  • The default border is 1.23:1 on white, a deliberately light look below WCAG 1.4.11's 3:1 for a field's edge; the faint shadow doesn't make up the difference. For 3.42:1, set --harmo-input-color-border: var(--harmo-color-border-control) on :root. Selects and textareas follow, since they share the token.