Back to Sentry

Input

static/app/components/core/input/input.mdx

26.5.27.3 KB
Original Source

import {Fragment, useState} from 'react';

import {Input} from '@sentry/scraps/input'; import {Stack} from '@sentry/scraps/layout';

import * as Storybook from 'sentry/stories';

export const documentation = import('!!type-loader!@sentry/scraps/input');

<Input> is a fundamental form component for capturing text input from users. It provides a consistent, accessible interface for text entry with support for various sizes, states, and behaviors.

Use <Input> when you need a simple text input field. For inputs with leading or trailing elements (like icons or buttons), use <InputGroup> or <InputControl> instead.

jsx
<Input placeholder="Enter your name" defaultValue="" />

Sizes

The <Input> component comes in three sizes: md (default), sm, and xs. Choose the size that matches your layout and content hierarchy.

export function SizesDemo() { return ( <Storybook.Grid columns={2}> <Stack gap="sm"> <span>size="md" (default)</span> <Input size="md" defaultValue="" /> </Stack> <Stack gap="sm"> <span>size="sm"</span> <Input size="sm" defaultValue="value" /> </Stack> <Stack gap="sm"> <span>size="xs"</span> <Input size="xs" defaultValue="" placeholder="placeholder" /> </Stack> </Storybook.Grid> ); }

<Storybook.Demo> <SizesDemo /> </Storybook.Demo>

jsx
<Input size="md" defaultValue="" />
<Input size="sm" defaultValue="value" />
<Input size="xs" defaultValue="" placeholder="placeholder" />

States

Inputs support three non-editable states: disabled, readOnly, and aria-disabled. These states prevent user input but communicate different meanings:

  • disabled: Input is completely non-interactive and not submitted with forms. Styled with reduced opacity.
  • readOnly: Input is non-editable but focusable, selectable, and submitted with forms. Styled like a disabled field.
  • aria-disabled: Styled like a disabled field but remains fully interactive (focusable, selectable, can trigger events). Useful when you need to prevent input but maintain interactivity for other purposes.

export function StatesDemo() { const [disabledValue, setDisabledValue] = useState('this is disabled'); const [ariaDisabledValue, setAriaDisabledValue] = useState('this is aria-disabled'); const [readonlyValue, setReadonlyValue] = useState('this is readonly'); return ( <Storybook.Grid columns={2}> <Stack gap="sm"> <span>disabled</span> <Input disabled value={disabledValue} onChange={e => setDisabledValue(e.target.value)} /> </Stack> <Stack gap="sm"> <span>aria-disabled</span> <Input aria-disabled value={ariaDisabledValue} onChange={e => setAriaDisabledValue(e.target.value)} /> </Stack> <Stack gap="sm"> <span>readOnly</span> <Input readOnly value={readonlyValue} onChange={e => setReadonlyValue(e.target.value)} /> </Stack> </Storybook.Grid> ); }

<Storybook.Demo> <StatesDemo /> </Storybook.Demo>

jsx
// Disabled: non-interactive, not submitted
<Input disabled value={value} onChange={setValue} />

// Aria-disabled: styled as disabled but remains interactive
<Input aria-disabled value={value} onChange={setValue} />

// Read-only: non-editable but focusable and submitted
<Input readOnly value={value} onChange={setValue} />

[!NOTE] Use readOnly when you want to display a value that should be submitted with the form but not edited. Use disabled when the input is temporarily unavailable. Use aria-disabled when you need the disabled appearance but want to maintain event handlers or focus behavior.

Monospace Font

Set the monospace prop to render the input with a monospace font family. This is useful for code, identifiers, or technical values.

<Storybook.Demo> <Input defaultValue="Regular font" /> <Input monospace defaultValue="Monospace font" /> </Storybook.Demo>

jsx
<Input defaultValue="Regular font" />
<Input monospace defaultValue="Monospace font" />

Native Size Attribute

The <Input> component uses the size prop for styling (controlling height and padding). To use the native HTML size attribute (which controls the number of characters the input should fit), use the nativeSize prop instead.

jsx
// Custom styling size (height/padding)
<Input size="sm" />

// Native size attribute (character width)
<Input nativeSize={20} />

// Both can be used together
<Input size="sm" nativeSize={10} />

Usage Patterns

Form Fields

Always pair inputs with labels for accessibility:

jsx
<label>
  Email Address
  <Input type="email" name="email" required />
</label>

Controlled Inputs

For controlled inputs, manage the value in React state:

jsx
const [email, setEmail] = useState('');

<Input
  type="email"
  value={email}
  onChange={e => setEmail(e.target.value)}
  placeholder="[email protected]"
/>;

Validation and Errors

Indicate validation state using ARIA attributes and visual cues:

jsx
<Input
  type="email"
  value={email}
  onChange={e => setEmail(e.target.value)}
  aria-invalid={!isValid}
  aria-describedby="email-error"
/>;
{
  !isValid && <div id="email-error">Please enter a valid email address</div>;
}

Accessibility

The <Input> component is built on the native <input> element and automatically meets several WCAG 2.2 AA standards:

Developer Responsibilities

To ensure your input implementations are fully accessible, follow these guidelines:

Labels (WCAG 3.3.2)

  • Every input must have an associated label. Use a <label> element with htmlFor, wrap the input in a <label>, or provide aria-label or aria-labelledby.
  • Labels should be clear and descriptive.
jsx
// Good: Visible label
<label htmlFor="email">Email Address</label>
<Input id="email" type="email" />

// Good: Wrapping label
<label>
  Email Address
  <Input type="email" />
</label>

// Good: aria-label for icon-only or context-clear inputs
<Input type="search" aria-label="Search issues" />

Error Identification (WCAG 3.3.1)

  • When validation fails, clearly identify the error to the user
  • Use aria-invalid="true" to programmatically indicate invalid inputs
  • Use aria-describedby to associate error messages with inputs
jsx
<Input
  id="email"
  type="email"
  value={email}
  aria-invalid={hasError}
  aria-describedby={hasError ? 'email-error' : undefined}
/>;
{
  hasError && (
    <span id="email-error" role="alert">
      Please enter a valid email address
    </span>
  );
}

Required Fields

  • Use the required attribute for required fields
  • Indicate required fields visually (e.g., with an asterisk in the label)

Placeholder Text

  • Don't rely solely on placeholder text for instructions or labels
  • Placeholders disappear when typing begins and may have contrast issues
  • Use placeholders for examples, not essential information

For more information, see the WAI-ARIA Text Input practices.