Monet
@etched/monet 0.0.1

Input

Ported

Single-line text field. Native <input> attributes and ref pass through.

import { Input } from "@etched/monet/input";

export function Preview() {
  return <Input aria-label="Search runs" placeholder="Search runs" />;
}

Installation

import { Input, InputArea } from "@etched/monet/input";

Examples

Sizes

import { Input, type InputSize } from "@etched/monet/input";

const sizes: InputSize[] = ["sm", "base"];

export function Sizes() {
  return (
    <div className="row">
      {sizes.map((s) => (
        <Input key={s} size={s} aria-label={`Search, ${s}`} placeholder={`Search (${s})`} />
      ))}
    </div>
  );
}

Labels and states

label, description and error wrap the input in a Field.

Shown on the run page.

Site TPE-9 does not exist.
import { Input } from "@etched/monet/input";

export function LabelsAndStates() {
  return (
    <div className="grid">
      <Input label="Run ID" defaultValue="run_7f3a91c2" />
      <Input label="Owner" placeholder="Name or email" description="Shown on the run page." />
      <Input label="Site" defaultValue="TPE-9" error="Site TPE-9 does not exist." />
      <Input label="Created by" defaultValue="system" disabled />
    </div>
  );
}

Read-only

readOnly keeps the value clear and selectable, on a quieter fill. Use it for values the user may copy but not change; disabled is for controls that are off.

import { Input, InputArea } from "@etched/monet/input";

export function ReadOnly() {
  return (
    <div className="grid">
      <Input label="Candidate ID" defaultValue="cand_2291a" readOnly />
      <InputArea label="Referral note" rows={2} defaultValue="Worked with Ana on the clock tree at her last job." readOnly />
    </div>
  );
}

Search and filter fields

passwordManagerIgnore keeps password managers from filling the field or offering to save it.

import { Input } from "@etched/monet/input";

export function SearchAndFilterFields() {
  return <Input type="search" aria-label="Filter candidates" placeholder="Filter candidates" passwordManagerIgnore />;
}

Input area

autoResize grows the field with its text between minRows and maxRows. onValueChange gets the new text on each change. Native attributes such as id reach the textarea.

Only the hiring team sees comments.

0 words

Add a reason before you reject.
import { useState } from "react";
import { InputArea } from "@etched/monet/input";

export function InputAreas() {
  const [notes, setNotes] = useState("");

  return (
    <div className="grid">
      <InputArea id="hiring-comment" label="Comment" rows={3} placeholder="Add a comment" description="Only the hiring team sees comments." />
      <InputArea
        label="Notes (grows from 2 to 6 rows)"
        autoResize
        minRows={2}
        maxRows={6}
        placeholder="Type several lines"
        value={notes}
        onValueChange={setNotes}
        description={`${notes.split(/\s+/).filter(Boolean).length} words`}
      />
      <InputArea label="Reason" error="Add a reason before you reject." />
    </div>
  );
}

Character limit

limit shows the count under the field. Past the limit, the count and the field turn red; nothing is cut off.

63 / 140
76 / 60
import { InputArea } from "@etched/monet/input";

export function CharacterLimit() {
  return (
    <div className="grid">
      <InputArea label="Note to the hiring manager" limit={140} defaultValue="Strong on clock trees; wants to stay close to silicon bring-up." />
      <InputArea
        label="Summary"
        limit={60}
        defaultValue="Led the clock tree rework on the last tape-out, and owned the bring-up plan."
      />
    </div>
  );
}

Accessibility

  • A native input (Input) or textarea (InputArea). With label, the label names it, and a click on the label focuses it.
  • description and error describe it through aria-describedby, and an error sets aria-invalid. The help text goes while an error shows.
  • With limit, the "n / limit" count also describes the field, and past the limit the field gets aria-invalid. The count is not a live region.
  • Without label, give it an aria-label. A placeholder is not a name.

API reference

InputArea

PropTypeDefaultDescription
minRowsnumber1
maxRowsnumber–
onValueChange(value: string) => void–Called with the new text on each change.
labelReactNode–Visible label. Without one, give the control an aria-label.
labelTooltipReactNode–More about the field, behind an info button after the label.
labelTooltipLabelstring"More information"Names the info button.
descriptionReactNode–Help text below the control. Hidden while an error shows.
errorFieldError–
size"sm" | "base""base"
autoResizeboolean–Grow and shrink with the text, between minRows and maxRows.
limitnumber–Shows "n / limit" under the field. Typing past it is allowed: the count and the field turn red, so no text is cut off without notice.
classNamestring–

Input

PropTypeDefaultDescription
labelReactNode–Visible label. Without one, give the control an aria-label.
labelTooltipReactNode–More about the field, behind an info button after the label.
labelTooltipLabelstring"More information"Names the info button.
descriptionReactNode–Help text below the control. Hidden while an error shows.
errorFieldError–
size"sm" | "base""base"
passwordManagerIgnoreboolean–Keeps password managers (1Password, Bitwarden, LastPass, Keeper) from filling the field or offering to save it. For search and filter fields.
classNamestring–