# OtpField

Accepts a one-time passcode, one character per slot.

[View source and API](https://github.com/tempoxyz/ds/blob/main/src/web/components/OtpField.tsx)

## Overview

An OTP field takes a one-time passcode, with a slot per character.

Label it with `Field.Label` or a `<label>`, which also names the first slot.

## Examples

### Basic

```tsx
import { OtpField, style } from '@tempoxyz/ds'
import { useState } from 'react'

const code = '123456'

const messages = {
  idle: `Enter ${code} to verify`,
  invalid: 'Wrong code. Delete a digit and try again.',
  success: 'Code accepted',
}

export function Demo() {
  const [value, setValue] = useState('')
  const status = (() => {
    if (value.length < code.length) return 'idle'
    if (value === code) return 'success'
    return 'invalid'
  })()

  return (
    <div {...styles.column()}>
      <OtpField.Root
        aria-label="Verification code"
        invalid={status === 'invalid'}
        length={6}
        onValueChange={setValue}
        success={status === 'success'}
        value={value}
      />
      <output>{messages[status]}</output>
    </div>
  )
}

namespace styles {
  export const column = style({
    alignItems: 'flex-start',
    display: 'flex',
    flexDirection: 'column',
    gap: '6',
  })
}
```

[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/OtpField/Basic.tsx)

### Size

Set `size` to `small`, `medium`, or `large`. It defaults to `medium`.

```tsx
import { OtpField, style } from '@tempoxyz/ds'

export function Demo() {
  return (
    <div {...styles.column()}>
      {(['small', 'medium', 'large'] as const).map((size) => (
        <OtpField.Root aria-label={`${size} code`} key={size} length={6} size={size} />
      ))}
    </div>
  )
}

namespace styles {
  export const column = style({
    alignItems: 'flex-start',
    display: 'flex',
    flexDirection: 'column',
    gap: '6',
  })
}
```

[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/OtpField/Size.tsx)

### Invalid

Set `invalid` to color the slots and nudge them sideways.

```tsx
import { OtpField, style } from '@tempoxyz/ds'

export function Demo() {
  return (
    <div {...styles.column()}>
      <OtpField.Root aria-label="Invalid code" defaultValue="000000" invalid length={6} />
    </div>
  )
}

namespace styles {
  export const column = style({
    alignItems: 'flex-start',
    display: 'flex',
    flexDirection: 'column',
    gap: '6',
  })
}
```

[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/OtpField/Invalid.tsx)

### Success

Set `success` to color the slots and pop them in sequence.

```tsx
import { OtpField, style } from '@tempoxyz/ds'

export function Demo() {
  return (
    <div {...styles.column()}>
      <OtpField.Root aria-label="Verified code" defaultValue="123456" length={6} success />
    </div>
  )
}

namespace styles {
  export const column = style({
    alignItems: 'flex-start',
    display: 'flex',
    flexDirection: 'column',
    gap: '6',
  })
}
```

[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/OtpField/Success.tsx)

### Disabled

```tsx
import { OtpField, style } from '@tempoxyz/ds'

export function Demo() {
  return (
    <div {...styles.column()}>
      <OtpField.Root aria-label="Disabled code" defaultValue="123" disabled length={6} />
    </div>
  )
}

namespace styles {
  export const column = style({
    alignItems: 'flex-start',
    display: 'flex',
    flexDirection: 'column',
    gap: '6',
  })
}
```

[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/OtpField/Disabled.tsx)

## Guidelines

TODO: Write guidelines for OtpField.
