Input

A text input component with support for icons, prefix/suffix, chips, and size variants.

Anatomy

Import and assemble the component:

1import { Input } from "@raystack/apsara";
2
3<Input placeholder="Enter text" />

For labels, description, and error messages, wrap with Field:

1import { Field, Input } from "@raystack/apsara";
2
3<Field label="Email" description="We won't share it" error={errors.email?.message}>
4 <Input placeholder="Enter email" />
5</Field>

Usage

An input can carry more than text. Icons, a prefix or suffix, and chips all sit inside the same frame.

Basic Input

A single-line text input. placeholder hints at the expected value; it is not a label and does not replace one.

1<Input placeholder="Enter text" />

Size

Input comes in two sizes: small (24px) and large (32px).

1<Flex direction="column" gap={5}>
2 <Input placeholder="32px height (default)" />
3 <Input placeholder="24px height" size="small" />
4</Flex>

With prefix and suffix

Prefix and suffix sit inside the field for fixed units and protocols: a currency symbol, https://, @. They are decoration, not part of the value.

1<Input placeholder="0.00" prefix="$" suffix="USD" />

With icons

A leading icon names the field at a glance; a trailing icon usually holds an action, like clear or reveal.

1<Input
2 placeholder="Enter text"
3 leadingIcon={<Home size={16} />}
4 trailingIcon={<Info size={16} />}
5/>

With chips

chips shows chips before the text. Each item is either Chip props, which the input renders as a Chip, or a Chip element, which renders as given.

1<Flex direction="column" gap={5}>
2 <Input
3 placeholder="Type and press Enter..."
4 chips={[{ children: "A" }, { children: "B" }]}
5 />
6 <Input
7 placeholder="Type and press Enter..."
8 size="small"
9 chips={[{ children: "A" }, { children: "B" }]}
10 />
11</Flex>

Interactive chips

To make a chip removable, pass a Chip element with a Chip.Remove child and handle the removal in its onClick.

maxChipsVisible caps how many are rendered before collapsing the rest into an overflow counter.

1chips?: Array<ReactElement | ChipProps>;
2maxChipsVisible?: number; // defaults to 2

The input does not manage chip state. The parent component owns the array and decides when items are added or removed.

The example below appends a chip on Enter and removes one when its remove button is clicked.

1const [chips, setChips] = React.useState([
2 { label: "Tag1" },
3 { label: "Tag2" },
4 { label: "Tag3" },
5 { label: "Tag4" },
6 { label: "Tag5" },
7]);
8const [input, setInput] = React.useState("");
9
10<Input
11 placeholder="Type and press Enter..."
12 value={input}
13 onChange={(e) => setInput(e.target.value)}
14 onKeyDown={(e) => {

With Field

Use Field to add label, description, and error handling.

1<Flex direction="column" gap={5} style={{ width: 560 }}>
2 <Field label="Email" required description="We won't share your email">
3 <Input type="email" placeholder="Enter email" />
4 </Field>
5 <Field label="Name" error="This field is required">
6 <Input placeholder="Enter name" />
7 </Field>
8 <Field label="Phone" required={false}>
9 <Input type="tel" placeholder="Enter phone" />
10 </Field>
11</Flex>

Controlled

Use onValueChange for a callback that receives only the new string value, or onChange for the full React change event. Both fire on every keystroke, so pick whichever fits your needs.

1(function ValueChangeExample() {
2 const [value, setValue] = React.useState("");
3
4 return (
5 <Flex direction="column" gap={5} style={{ width: 400 }}>
6 <Input
7 placeholder="Type something..."
8 value={value}
9 onValueChange={setValue}
10 />
11 <Text size="small">Current value: {value || "(empty)"}</Text>
12 </Flex>
13 );
14})

Disabled

disabled stops interaction and removes the field from the tab order. Use readOnly instead when the value still needs to be selectable and copyable.

1<Input placeholder="Enter text" disabled />

Disabled with chips

When disabled, chips passed as props are disabled too, and so is their Chip.Remove. Chip elements render as given, so pass disabled to them yourself.

1<Input
2 placeholder="Type and press Enter..."
3 disabled
4 chips={[{ children: "Tag1" }, { children: "Tag2" }]}
5/>

API Reference

Renders a text input control. For label, description, and error support, use with Field.

Prop

Type

Slots

Every rendered part carries a stable data-slot attribute for styling and testing:

SlotElement
input-containerThe outer wrapper <div>
input-leading-iconWrapper around the leading icon (when leadingIcon)
input-prefixThe prefix text (when prefix)
input-chip-containerWrapper around the chips and the <input> element
input-chipEach visible chip (when chips)
input-chip-overflowThe +N overflow count (when chips exceed maxChipsVisible)
inputThe <input> element itself
input-suffixThe suffix text (when suffix)
input-trailing-iconWrapper around the trailing icon (when trailingIcon)

Accessibility

  • Use with Field for automatic label association and error linking
  • Required state is communicated via aria-required
  • Supports all native <input> attributes
  • The leading icon is hidden from screen readers. The trailing icon is not, so a button in it stays reachable. Set aria-hidden on decorative content in trailingIcon that is not an icon, for example a text glyph.