suiss/uim · React Native Component

Input Group

An input or textarea combined with prefix and suffix addons such as text, icons and buttons.

Input Group is an open-source mobile component from suiss/uim for React Native and Expo, with SwiftUI and Jetpack Compose versions built from the same design tokens. The @esuiss/uim CLI copies its source into your project, so you own the code.

iOS
Input Group on iOS in light mode

InputGroup draws one control-colored field and places an InputGroupInput or InputGroupTextarea inside it with addons around. Addons can sit on the start or end of the same line (inline-start, inline-end), or above or below the input (block-start, block-end), which turns the group into a column.

The group shows the focus border while its input is focused, and reads the disabled and invalid state from a surrounding Field. Pressing an addon focuses the input.

Installation

$ pnpm dlx @esuiss/uim@latest add input-group

The CLI also adds what it builds on: Button, Icon, Input, Text, Textarea.

Manual

  1. Install the dependencies:
npx expo install class-variance-authority cn
  1. Add the pieces it builds on: Button, Icon, Input, Text, Textarea, and the primitives components/primitives/field.tsx, components/primitives/use-render.tsx.

  2. Copy the source into components/ui/input-group.tsx:

uniwind/components/ui/input-group.tsx
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "cn"
import * as React from "react"
import { Pressable, type TextInput, View, type ViewProps } from "react-native"
import { useFieldRootContext } from "@/components/primitives/field"
import { resolveClassName } from "@/components/primitives/use-render"
import { Button } from "@/components/ui/button"
import { IconClassContext } from "@/components/ui/icon"
import { Input } from "@/components/ui/input"
import { Text, TextClassContext } from "@/components/ui/text"
import { Textarea } from "@/components/ui/textarea"

type InputGroupAlign =
  | "inline-start"
  | "inline-end"
  | "block-start"
  1. Update the import paths to match your project.

Usage

import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupText, InputGroupInput, InputGroupTextarea } from "@/components/ui/input-group"
<View className="gap-4">
  <SearchDemo />
  <InputGroup>
    <InputGroupAddon>
      <InputGroupText>https://</InputGroupText>
    </InputGroupAddon>
    <InputGroupInput placeholder="example.com" autoCapitalize="none" />
    <InputGroupAddon align="inline-end">
      <InputGroupText>.com</InputGroupText>
    </InputGroupAddon>
  </InputGroup>
  <InputGroup>
    <InputGroupInput defaultValue="sk_live_51H8" />
    <InputGroupAddon align="inline-end">
      <InputGroupButton size="icon-xs" accessibilityLabel="Copy">
        <Icon as={CopyIcon} />
      </InputGroupButton>
    </InputGroupAddon>
  </InputGroup>
  <InputGroup>
    <InputGroupInput placeholder="Searching..." />
    <InputGroupAddon align="inline-end">
      <Spinner />
    </InputGroupAddon>
  </InputGroup>
  <InputGroup invalid>
    <InputGroupInput defaultValue="not-an-email" />
    <InputGroupAddon align="inline-end">
      <InputGroupText>Invalid</InputGroupText>
    </InputGroupAddon>
  </InputGroup>
  <InputGroup disabled>
    <InputGroupInput placeholder="Disabled" />
    <InputGroupAddon>
      <Icon as={MagnifyingGlassIcon} />
    </InputGroupAddon>
  </InputGroup>
</View>

Add children in any order; the group sorts start addons before the input and end addons after it. Put short labels such as a URL prefix or a unit in InputGroupText, and actions in InputGroupButton, a small rounded Button that defaults to the ghost variant and xs size.

Use a block-end addon with InputGroupTextarea for a footer row, for example a character count and a send button. Set invalid or disabled on the group, or let a Field provide them.

Examples

With textarea

A textarea with a footer row holding a usage label and a button.

iOS
Input Group (with textarea) on iOS in light mode

Block start

A label addon above the input with block-start.

iOS
Input Group (block start) on iOS in light mode

API Reference

InputGroup

Field container that lays out the input and addons.

ExtendsViewProps
PropType
About
Disables the group and its input.
Type
boolean
Default
false
About
Shows the danger border and tint.
Type
boolean
Default
—

InputGroupAddon

Slot for text, icons or buttons beside or around the input.

ExtendsReact.ComponentProps<typeof Pressable>
PropType
About
inline-start, inline-end, block-start or block-end. Defaults to inline-start.
Type
"inline-start""inline-end""block-start""block-end"
Default
"inline-start"

InputGroupButton

Compact button inside an addon.

ExtendsReact.ComponentProps<typeof Button>
PropType
About
xs, sm, icon-xs or icon-sm. Defaults to xs.
Type
keyof typeof BUTTON_SIZE
Default
"xs"

InputGroupText

Text inside an addon.

ExtendsReact.ComponentProps<typeof Text>

InputGroupInput

Single-line input without its own border.

ExtendsReact.ComponentProps<typeof Input>

InputGroupTextarea

Multi-line input without its own border.

ExtendsReact.ComponentProps<typeof Textarea>

Accessibility

  • The container has the group role.
  • Addons are not separate accessibility elements; their text is not announced with the input, so give the input an accessibilityLabel that includes needed context.
  • Icon-only buttons need an accessibilityLabel.

Notes

  • Uses bg-control, border-focus, border-danger and bg-control-disabled tokens; the invalid tint is stronger in dark mode.
  • Light and dark follow the system appearance.