npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@starasia/input

v4.2.0

Published

input component for starasia UI

Readme

@starasia/input

A flexible, design-system-driven input component for React. Implements the Starasia "TextField" Figma spec — three variants × four sizes × eight states × three label positions, plus currency formatting, autocomplete, and a built-in clear button.

Installation

pnpm add @starasia/input
# or
yarn add @starasia/input
# or
npm i @starasia/input

Quick start

import {Input} from "@starasia/input";

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

  return (
    <Input
      label="Email"
      required
      placeholder="[email protected]"
      helperText="We'll never share your email."
      value={value}
      onChange={(e) => setValue(e.target.value)}
    />
  );
}

Props

Layout & sizing

| Prop | Type | Default | Description | | --------------- | ------------------------------------------------- | -------------- | -------------------------------------------- | | size | "sm" \| "md" \| "lg" \| "xl" | "md" | Field height & typography scale. | | variant | "standard" \| "outline" \| "flushed" | "outline" | Visual style of the input box. | | status | "default" \| "error" \| "success" \| "disable" | "default" | Border color & helper-text styling. | | labelPosition | "outside-top" \| "outside-left" \| "inside" | "outside-top"| Where the label sits relative to the field. | | fullWidth | boolean | false | Stretch the component to fill its container. |

Label & helpers

| Prop | Type | Description | | ------------- | ----------- | ---------------------------------------------------------------------------- | | label | ReactNode | Field label. | | required | boolean | Show a red * next to the label. | | optional | boolean | Show an "Optional" pill next to the label. | | description | string | Subtle help text rendered above the field. | | helperText | string | Subtle help text rendered below the field. | | errorText | string | Red error text rendered below the field — only shown when status="error". |

Adornments

| Prop | Type | Description | | ------------------- | -------------------------- | -------------------------------------------------------------------------- | | leftIcon | ReactElement | SVG element placed inside the field on the left. | | rightIcon | ReactElement | SVG element placed inside the field on the right. | | onClickLeftIcon | () => void | Click handler for the left icon (icon container becomes clickable). | | onClickRightIcon | () => void | Click handler for the right icon. | | leftAddons | ReactNode | Block content attached to the left edge (e.g. "https://"). | | rightAddons | ReactNode | Block content attached to the right edge (e.g. ".com"). |

Behavior

| Prop | Type | Default | Description | | ---------------------- | -------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------- | | clearable | boolean | true | Show a × button to clear the value when the field has content. The slot is reserved so the input width stays constant. | | onClear | () => void | | Fires after the clear button is pressed. | | currency | boolean | false | Format the value as 1.234.567 while typing. onChange receives the raw numeric string. Caret stays in place when editing in the middle. | | highlightPlaceholder | string | | Substring of the placeholder rendered in the primary text color (visual emphasis only — placeholder stays inert). | | options | string[] | | Enables an autocomplete dropdown filtered against the current value. | | onOptionChange | (value: string) => void | | Fires when the user picks an option from the dropdown. |

All other native <input> HTML attributes (name, type, disabled, onFocus, onBlur, onKeyDown, value, defaultValue, …) are forwarded to the underlying element.

Variants

<Input variant="standard"   label="Standard"   /> {/* filled gray box, no border  */}
<Input variant="outline"    label="Outline"    /> {/* white box, 0.8px border     */}
<Input variant="flushed"    label="Flushed"    /> {/* bottom border only          */}
<Input variant="borderless" label="Borderless" /> {/* transparent, no border      */}

Sizes

sm (32 px) · md (40 px) · lg (48 px) · xl (56 px). Sizes affect typography and helper-text scale too — sm uses 12 px input text and 10 px helpers; the others use 14 px input text and 12 px helpers.

Status

<Input status="default" />                                      {/* subtle border       */}
<Input status="error" errorText="Please enter a valid email." />{/* red border + red text */}
<Input status="success" helperText="Email is available." />     {/* green border + ✓ icon */}
<Input status="disable" />                                      {/* greyed out           */}

status="success" automatically renders a green checkmark on the right side of the field.

Label positions

outside-top (default)

<Input
  label="Field label"
  required
  optional
  description="Enable multi-factor authentication."
  placeholder="[email protected]"
  helperText="I am some friendly help text."
/>

outside-left

The label and description occupy a column to the left of the field.

<Input
  fullWidth
  labelPosition="outside-left"
  label="Field label"
  description="Enable multi-factor authentication."
  placeholder="[email protected]"
  helperText="I am some friendly help text."
/>

inside (floating label)

The label sits inside the field at rest. As soon as the field is focused or has a value, the label animates upward (font size shrinks, color changes) and the input field appears below — animation is 180 ms cubic-bezier(0.4, 0, 0.2, 1).

<Input
  labelPosition="inside"
  label="Field label"
  required
  rightIcon={<IcMail />}
  helperText="Click to start typing."
/>

Adornments

<Input leftIcon={<IcSearch />} placeholder="Search…" />
<Input rightIcon={<IcEye />} placeholder="Password" />
<Input
  leftIcon={<IcSearch />}
  onClickLeftIcon={() => doSomething()}
  rightIcon={<IcQrCode />}
  onClickRightIcon={() => scanQr()}
/>
<Input leftAddons="https://" placeholder="yourdomain.com" />
<Input rightAddons=".com" placeholder="yourdomain" />
<Input leftAddons="Rp" rightAddons=",-" placeholder="Nominal" />

Pass onClickLeftIcon / onClickRightIcon to make an icon clickable. The component wraps the icon in its own clickable container — your icon's own onClick is not consumed.

Clear button

The × clear button appears automatically whenever the field has a value and is not disabled. The slot is always reserved, so the input width stays constant whether or not the × is visible — the button just fades in/out.

<Input clearable />              {/* default: true */}
<Input clearable={false} />      {/* opt out      */}
<Input onClear={() => track()} />

Currency

const [amount, setAmount] = useState("");

<Input
  currency
  leftAddons="Rp"
  placeholder="0"
  value={amount}
  onChange={(e) => setAmount(e.target.value)} // raw "12345"
/>

While typing, the field displays 12.345 (thousands separator). The value delivered to onChange is the raw numeric string (no separators), so it can be saved or sent as-is. Editing in the middle of the value preserves the caret position; backspacing on a thousands separator deletes the digit before it.

Autocomplete

const [value, setValue] = useState("");

<Input
  label="Fruit"
  placeholder="Type to filter…"
  value={value}
  onChange={(e) => setValue(e.target.value)}
  options={["Apple", "Banana", "Cherry", "Durian"]}
  onOptionChange={(picked) => setValue(picked)}
/>

Options are filtered by startsWith against the current value and rendered in a floating dropdown.

Highlight placeholder

<Input
  placeholder="Full Name (Required)"
  highlightPlaceholder="Required"
/>

The matched substring is rendered in the primary text color while the rest of the placeholder stays subtle.

Imperative ref

Input forwards a ref to the underlying <input> element — useful for focus management, integrating with form libraries, etc.

const ref = useRef<HTMLInputElement>(null);

<Input ref={ref} />

// later
ref.current?.focus();

Design tokens

The component reads its colors from CSS custom properties prefixed with --sa-input-*. The defaults match the Starasia Figma library; override them on your :root (or any ancestor) to retheme:

| Token | Default | Used for | | ------------------------------- | ------------------------ | ------------------------------- | | --sa-input-text-primary | #292a2e | Input value & label | | --sa-input-text-subtle | #505258 | Standard placeholder | | --sa-input-text-subtlest | #6b6e76 | Helper / description / outline placeholder | | --sa-input-text-error | #a4133c | Error text | | --sa-input-border-subtle | rgba(11,18,14,0.14) | Default border | | --sa-input-border-brand | #1976d2 | Focus border | | --sa-input-border-brand-subtle| #90caf9 | Focus ring (inside-label) | | --sa-input-border-danger | #c9184a | Error border | | --sa-input-border-danger-subtle| #ffb3c1 | Error focus ring | | --sa-input-border-success | #28ac6e | Success border | | --sa-input-border-disabled | rgba(24,26,25,0.56) | Disabled border | | --sa-input-bg-neutral | #f0f1f2 | Standard variant background | | --sa-input-bg-error-subtlest | #fff0f3 | Standard + error background | | --sa-input-bg-success-subtlest| #ecfff6 | Standard + success background |

TypeScript

All public types are exported alongside the component:

import type {
  IInputProps,
  InputSize,
  InputVariant,
  InputStatus,
  InputLabelPosition,
} from "@starasia/input";

License

ISC