# Input (/docs/input)





## API Reference [#api-reference]

<BaseUIReference href="https://base-ui.com/react/components/input" />

## Basic [#basic]

<Preview cssProperties="inputPlaygroundCssProperties">
  <InputExample />

  <Preview.Code>
    {`
          import { Field, FieldLabel, Input } from "moduix";

          export function InputDemo() {
            return (
              <Field className={styles.field}>
                <FieldLabel>Name</FieldLabel>
                <Input placeholder="Enter your name" />
              </Field>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .field {
            width: min(20rem, 100%);
          }
        `}
  </Preview.CSS>

  <Preview.CSSProperties>
    {(context) => <InputCssPropertiesPanel {...context} />}
  </Preview.CSSProperties>

  <Preview.CSSPlayground>
    {(context) => <InputCssPlaygroundPanel {...context} />}
  </Preview.CSSPlayground>
</Preview>

## Anatomy [#anatomy]

`Input` is composed as a single native input root. It is commonly composed inside `Field` for labels,
descriptions, and validation messaging.

```text
Field (optional wrapper)
└─ Input
```

| Part    | Role                                                                     |
| ------- | ------------------------------------------------------------------------ |
| `Input` | Native input element with Base UI state integration and style variables. |

## Composition [#composition]

Use `Input` props such as `value`, `defaultValue`, `onValueChange`, `render`, function `className`,
function `style`, and Field state data attributes from Base UI.

Use `size` for the visual component size. Use `htmlSize` for the native HTML `size` attribute:

```tsx
<Input size="lg" htmlSize={24} placeholder="Search projects" />
```

`Input` does not render hidden service slots such as `Positioner`, `Backdrop`, or `Viewport`, so it
does not need a `classNames` API. Style the input element directly with `className`.

The package exports Base UI event and state types for controlled inputs and styling callbacks:

```tsx
import { type InputChangeEventDetails, type InputChangeEventReason, type InputState } from 'moduix';
```

## Examples [#examples]

### Controlled [#controlled]

Use `value` and `onValueChange` when the input value needs to stay in React state.

<Preview>
  <ControlledInputExample />

  <Preview.Code>
    {`
          import { Field, FieldLabel, Input } from "moduix";
          import { useState } from "react";

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

            return (
              <Field className={styles.field}>
                <FieldLabel>Username</FieldLabel>
                <Input
                  value={value}
                  onValueChange={setValue}
                  placeholder="Type to control value"
                />
              </Field>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .field {
            width: min(20rem, 100%);
          }
        `}
  </Preview.CSS>
</Preview>

### Sizes [#sizes]

Use the `size` prop for visual sizing. Use `htmlSize` when you need the native input `size` attribute.

<Preview>
  <InputSizesExample />

  <Preview.Code>
    {`
          import { Input } from "moduix";

          export function InputSizesDemo() {
            return (
              <div className={styles.stack}>
                <Input size="xs" placeholder="Extra-small input" />
                <Input size="sm" placeholder="Small input" />
                <Input size="md" placeholder="Medium input" />
                <Input size="lg" placeholder="Large input" />
                <Input size="xl" placeholder="Extra-large input" />
              </div>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .stack {
            display: grid;
            gap: var(--spacing-3);
            width: min(20rem, 100%);
          }
        `}
  </Preview.CSS>
</Preview>

### Native Attributes [#native-attributes]

Use standard input attributes for keyboard, autocomplete, validation, and form behavior. The `htmlSize` prop maps to the native `size` attribute because `size` controls the visual component size.

<Preview>
  <InputNativeAttributesExample />

  <Preview.Code>
    {`
          import { Field, FieldLabel, Input } from "moduix";

          export function NativeInputAttributesDemo() {
            return (
              <Field className={styles.field}>
                <FieldLabel>Security code</FieldLabel>
                <Input
                  htmlSize={8}
                  inputMode="numeric"
                  maxLength={6}
                  name="security-code"
                  placeholder="000000"
                  type="text"
                  autoComplete="one-time-code"
                />
              </Field>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .field {
            width: min(20rem, 100%);
          }
        `}
  </Preview.CSS>
</Preview>

### Disabled [#disabled]

Set `disabled` to prevent interaction while keeping the input visible in forms.

<Preview>
  <DisabledInputExample />

  <Preview.Code>
    {`
          import { Input } from "moduix";

          export function DisabledInputDemo() {
            return (
              <div className={styles.stack}>
                <Input disabled placeholder="Disabled input" />
                <Input disabled value="Read only value" />
              </div>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .stack {
            display: grid;
            gap: var(--spacing-3);
            width: min(20rem, 100%);
          }
        `}
  </Preview.CSS>
</Preview>

### Field Validation [#field-validation]

Place `Input` inside `Field` to connect labels, errors, native validity, and Base UI data attributes.

<Preview>
  <InputFieldValidationExample />

  <Preview.Code>
    {`
          import { Field, FieldLabel, Input, FieldError } from "moduix";

          export function InputFieldValidationDemo() {
            return (
              <Field className={styles.field} validationMode="onBlur">
                <FieldLabel>Email</FieldLabel>
                <Input required type="email" placeholder="name@example.com" />
                <FieldError match="valueMissing">Please enter your email.</FieldError>
                <FieldError match="typeMismatch">Enter a valid email address.</FieldError>
              </Field>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .field {
            width: min(20rem, 100%);
          }
        `}
  </Preview.CSS>
</Preview>

### Custom Styles [#custom-styles]

Pass `className` directly to `Input` when styling with CSS Modules, Tailwind CSS, or CSS-in-JS.

<Preview>
  <CustomStylesInputExample />

  <Preview.Code>
    {`
          import { Field, FieldLabel, Input } from "moduix";

          export function CustomInputDemo() {
            return (
              <Field className={styles.field}>
                <FieldLabel>Project key</FieldLabel>
                <Input placeholder="MAPS" className={styles.customInput} />
              </Field>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .field {
            width: min(20rem, 100%);
          }

          .customInput {
            border-color: color-mix(in srgb, var(--color-primary) 40%, transparent);
            background-color: color-mix(in srgb, var(--color-primary) 5%, transparent);
            color: var(--color-primary);
            text-transform: uppercase;
            letter-spacing: 0;
          }

          .customInput::placeholder {
            text-transform: none;
          }

          .customInput:focus {
            outline-color: var(--color-primary);
          }
        `}
  </Preview.CSS>
</Preview>
