Welcome to Oshon · v1.0  ·  Now in public beta for enterprise teams Read the launch notes
Text InputsUpdatedFree

Input Fields

Standard / Dropdown / Split L+R / Text Area / Link Field.

Preview

Live preview
@oshon-ai/components

We'll never share your email.

Up to 1024 characters.

Installation

Install the runtime packages:

pnpm
pnpm add @oshon-ai/components @oshon-ai/tokens @oshon-ai/primitives

Or scaffold the component source directly into your codebase (shadcn-style):

pnpm
pnpm dlx @oshon-ai/cli add inputfields

Wire the tokens into your Tailwind v4 stylesheet:

css
/* app/globals.css */
@import 'tailwindcss';
@import '@oshon-ai/tokens/css';
@import '@oshon-ai/tokens/tailwind';

New here? Walk through the full setup — prereqs, theming, your first render.

Usage

Import the component and render it. Every component supports the standard tier, size, and disabled props where applicable.

tsx
'use client';
import { InputFields } from '@oshon-ai/components';

export default function Example() {
  return <InputFields />;
}

Basic — controlled

We'll never share your email.

Value: (empty)
tsx
<BasicField />

Validation — live errors

Your legal name as it appears on ID.

8+ characters.

Fill every field to submit.
tsx
<ValidationPlayground />

State matrix — Desktop (m)

Enabled

Optional Description

Active (focused — click to see)

Optional Description

Filled

Optional Description

ErrorFilled

ErrorEmpty

DisabledFilled

Optional Description

DisabledEmpty

Optional Description

tsx
<div style={stackCol}>
      <p style={sectionHeading}>Enabled</p>
      <TextField label="Label" required tooltip description="Optional Description" />

      <p style={sectionHeading}>Active (focused — click to see)</p>
      <TextField
        label="Label"
        required
        tooltip
        description="Optional Description"
        autoFocus
        defaultValue="User ente"
      />

      <p style={sectionHeading}>Filled</p>
      <TextField
        label="Label"
        required
        tooltip
        description="Optional Description"
        defaultValue="User entered text"
      />

      <p style={sectionHeading}>ErrorFilled</p>
      <TextField
        label="Label"
        required
        tooltip
        defaultValue="User entered text"
        error="Mandatory Error Description"
      />

      <p style={sectionHeading}>ErrorEmpty</p>
      <TextField
        label="Label"
        required
        tooltip
        error="Mandatory Error Description"
      />

      <p style={sectionHeading}>DisabledFilled</p>
      <TextField
        label="Label"
        required
        tooltip
        description="Optional Description"
        defaultValue="User entered text"
        disabled
      />

      <p style={sectionHeading}>DisabledEmpty</p>
      <TextField
        label="Label"
        required
        tooltip
        description="Optional Description"
        disabled
      />
    </div>

State matrix — Mobile

Enabled

Optional Description

Filled

Optional Description

ErrorFilled

DisabledFilled

Optional Description

tsx
<div style={stackCol}>
      <p style={sectionHeading}>Enabled</p>
      <TextField
        size="mobile"
        label="Label"
        required
        tooltip
        description="Optional Description"
      />

      <p style={sectionHeading}>Filled</p>
      <TextField
        size="mobile"
        label="Label"
        required
        tooltip
        description="Optional Description"
        defaultValue="User entered text"
      />

      <p style={sectionHeading}>ErrorFilled</p>
      <TextField
        size="mobile"
        label="Label"
        required
        tooltip
        defaultValue="User entered text"
        error="Mandatory Error Description"
      />

      <p style={sectionHeading}>DisabledFilled</p>
      <TextField
        size="mobile"
        label="Label"
        required
        tooltip
        description="Optional Description"
        defaultValue="User entered text"
        disabled
      />
    </div>

Size ladder — xs → mobile

Proportional to Figma scale.

Proportional to Figma scale.

Proportional to Figma Desktop.

Proportional to Figma scale.

Proportional to Figma Mobile.

tsx
<SizeLadderPlayground />

Secondary action slot

Optional Description

tsx
<SecondaryActionPlayground />

Form layout (2-col grid)

Optional

tsx
<FormPlayground />

API

Every prop is documented here directly from the component's TypeScript interface. Inherited DOM attributes (aria-*, onClick, style, etc.) work as usual but are omitted from this table.

PropTypeDefaultDescription
classNamestringClasses merged onto the underlying `<input>` (same as `Input`'s `className`).
descriptionReactNodeDescription shown under the field. Rendered as the "description" slot in Figma. Skipped if `error` is present.
disabledbooleanDisable the input. Renders with the native `disabled` attribute so screen readers and keyboard users get consistent signal. No change / blur audit events fire while disabled.
errorReactNodeError message shown under the field. When present, the helper row switches to the error slot, the input gets `aria-invalid="true"`, and the error is wired via `aria-describedby`.
invalidbooleanMarks the field as invalid for a11y. `true` → `aria-invalid="true"`. The visual layer surfaces the error styling; primitive only ensures correct ARIA.
labelReactNodeLabel content. If omitted, the label row is skipped.
permissionAttrsRecord<string, unknown>Attribute bag forwarded to `permissions.can(..., attrs)` for attribute-based access control. Primitives never invent values here — the consumer supplies them.
permissionsPartial<PermissionContext>Per-instance permission override. Merges over the ambient `PermissionContext`. Example: `permissions={{ mode: 'hidden' }}` switches this one instance to render-as-null when denied.
readOnlybooleanNon-mutating but still interactive. Renders with native `readOnly` so the field is focus-reachable, copy-friendly, and announced as read-only by assistive tech. Change events are silently dropped.
requiredbooleanRender the required asterisk next to the label AND set `aria-required` on the input. Native `required` is intentionally NOT forwarded — we let consumers own validity messaging via the `error` prop instead of letting the browser race with our helper row.
resourcestringResource name passed to `permissions.can('edit', resource, attrs)`. Default `'input'`. Consumers override for specific semantics, e.g. `resource="field:ssn"` for a sensitive data field.
secondaryActionReactNodeRight-justified slot inside the label row — the Figma "secondary action" placeholder. Typical usage: a checkbox or small control.
sizeenummVisual size. Default `'m'`.
tooltipReactNodeTooltip icon content. When provided, an info icon renders next to the required asterisk; consumers wrap this in their own Tooltip component if a hover hint is desired (omitting the wrapper gives a non-interactive visual hint).
wrapperClassNamestringClasses merged onto the outermost wrapper (the vertical stack).

Styling

Three layers of customization, in order of escape-hatch strength: className overrides → data-attribute targeting → CSS custom properties.

Passing Tailwind classes

Every Oshon component accepts a className prop merged AFTER the component's default classes. Use it to override spacing, color, or size without forking the component.

tsx
<InputFields
  className="ring-2 ring-offset-2 ring-blue-500"
/>

Data attributes

Oshon components expose their internal state as data-oshon-* attributes so you can target them from CSS without coupling to internal class names. The most common attributes are listed below — see the component's source for the full set.

AttributeValuesDescription
data-oshon-sizexs · s · m · l · mobileVisual size axis. Mirrors the `size` prop.
data-oshon-tierprimary · secondary · tertiaryVisual emphasis tier (Button family). Mirrors the `tier` prop.
data-oshon-stateenabled · active · error · disabledComponent surface state. Set automatically based on props.
data-disabledtrue · (omitted)Set when `disabled` is true. Pair with `:disabled` CSS for native input components.
data-stateopen · closed · checked · unchecked · …Radix-derived state for overlay components (Dialog, Tabs, Toggle, etc.).
css
/* Target the secondary tier specifically */
[data-oshon-tier="secondary"] {
  --oshon-color-primary-700: var(--my-brand-color);
}

Interactive states

Every interactive component supports the standard CSS pseudo- classes plus Tailwind's state variants. Focus rings always use :focus-visible so keyboard users see them but mouse users don't.

  • :hover / hover:* — pointer hover
  • :focus-visible / focus-visible:* — keyboard focus
  • :active / active:* — pressed
  • :disabled / disabled:* — set via the disabled prop