Input

Input renders text fields. North uses it instead of raw <input> elements. The parent owns the value and validation messages.

import Input from "@haloid/azucar/ui/input";

Variants

variant accepts primary, filled, ghost, and outlined. The default is primary.

primary and ghost have no surface. Use them inside controls that provide their own surface.

filled draws a gray well. It is 32px tall with medium-weight text.

outlined draws a bordered field with a white surface. It is 48px tall and fills its container.

variant
<div className="w-80"><Input variant="outlined" className="w-full" placeholder="Enter a value" /></div>

Labels

Set label to render a visible label. Input connects it to the field with an ID.

The component generates a unique ID when the parent does not provide one. Native attributes pass through to the input.

<div className="w-80">
<Input
  label="Email"
  name="email"
  type="email"
  autoComplete="email"
  placeholder="you@example.com"
  variant="outlined"
  required
/>
</div>

Values

Use value and onChange for a controlled field. Use defaultValue for an uncontrolled field.

type defaults to text. Set it to email, password, or another native input type as needed.

All variants forward native handlers, validation attributes, ARIA attributes, and refs. The filled variant also forwards onKeyDown, onBlur, and style.

Trailing controls

trailing places a control at the right edge. The field reserves space for it.

Give icon-only buttons an accessible name. Use Button with its default type so the trailing action does not submit the form.

<Input
label="Password"
variant="outlined"
type={visible ? "text" : "password"}
autoComplete="current-password"
trailing={
<Button
variant="ghost"
className="h-12 w-12"
aria-label={visible ? "Hide password" : "Show password"}
aria-pressed={visible}
onClick={() => setVisible((current) => !current)}
>
{visible ? <SFEyeSlash size={18} /> : <SFEye size={18} />}
</Button>
}
/>

Import Button from @haloid/azucar/ui/button and the icons from sf-symbols-lib/dualtone.

Focus and validation

outlined draws a focus ring around the field and its trailing control. The border darkens when the input receives focus.

Set aria-invalid to show an invalid border. Use aria-describedby to connect validation text to the input.

The other variants rely on their surrounding control for focus styling. ButtonWithInput, for example, retains its expanded surface.

API

interface Props extends ComponentPropsWithRef<"input"> {
variant?: "primary" | "filled" | "ghost" | "outlined";
label?: string;
trailing?: ReactNode;
}

className styles the input. label and trailing add wrappers; unlabeled primary, filled, and ghost fields retain their bare structure.

Use in north

The login page uses outlined fields with visible labels and native email validation. Its password field provides a visibility button.

ButtonWithInput uses primary fields and owns the surrounding surface. Search fields retain their existing appearance.