# NumberField

A numeric input with increment and decrement buttons.

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

## Overview

A number field is a numeric text input with decrement and increment buttons.

Use it for quantities adjusted in small steps. Use `Input` for codes and identifiers.

## Examples

### Basic

```tsx
import { NumberField } from '@tempoxyz/ds'

export function Demo() {
  return (
    <NumberField.Root defaultValue={3}>
      <NumberField.Group>
        <NumberField.Decrement />
        <NumberField.Input aria-label="Quantity" />
        <NumberField.Increment />
      </NumberField.Group>
    </NumberField.Root>
  )
}
```

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

### Size

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

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

function Example(
  props: Pick<NumberField.Root.Props, 'defaultValue' | 'disabled' | 'max' | 'min' | 'step'> &
    Pick<NumberField.Group.Props, 'invalid' | 'size'>,
) {
  const { invalid, size, ...root } = props

  return (
    <NumberField.Root {...root}>
      <NumberField.Group invalid={invalid} size={size}>
        <NumberField.Decrement />
        <NumberField.Input aria-label="Quantity" />
        <NumberField.Increment />
      </NumberField.Group>
    </NumberField.Root>
  )
}

export function Demo() {
  return (
    <div {...styles.grid()}>
      <Example defaultValue={24} size="small" />
      <Example defaultValue={12} size="medium" />
      <Example defaultValue={3} size="large" />
    </div>
  )
}

namespace styles {
  export const grid = style({
    alignItems: 'start',
    display: 'grid',
    gap: '3',
    gridTemplateColumns: 'repeat(auto-fill, minmax(240px, 1fr)) !custom',
    maxWidth: '520px !custom',
  })
}
```

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

### Min

Set `min` and `max` on `NumberField.Root` to bound the value.

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

function Example(
  props: Pick<NumberField.Root.Props, 'defaultValue' | 'disabled' | 'max' | 'min' | 'step'> &
    Pick<NumberField.Group.Props, 'invalid' | 'size'>,
) {
  const { invalid, size, ...root } = props

  return (
    <NumberField.Root {...root}>
      <NumberField.Group invalid={invalid} size={size}>
        <NumberField.Decrement />
        <NumberField.Input aria-label="Quantity" />
        <NumberField.Increment />
      </NumberField.Group>
    </NumberField.Root>
  )
}

export function Demo() {
  return (
    <div {...styles.grid()}>
      <Example defaultValue={0} min={0} />
      <Example defaultValue={10} max={10} />
    </div>
  )
}

namespace styles {
  export const grid = style({
    alignItems: 'start',
    display: 'grid',
    gap: '3',
    gridTemplateColumns: 'repeat(auto-fill, minmax(240px, 1fr)) !custom',
    maxWidth: '520px !custom',
  })
}
```

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

### Invalid

Set `invalid` on `NumberField.Group` to mark the value as rejected.

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

function Example(
  props: Pick<NumberField.Root.Props, 'defaultValue' | 'disabled' | 'max' | 'min' | 'step'> &
    Pick<NumberField.Group.Props, 'invalid' | 'size'>,
) {
  const { invalid, size, ...root } = props

  return (
    <NumberField.Root {...root}>
      <NumberField.Group invalid={invalid} size={size}>
        <NumberField.Decrement />
        <NumberField.Input aria-label="Quantity" />
        <NumberField.Increment />
      </NumberField.Group>
    </NumberField.Root>
  )
}

export function Demo() {
  return (
    <div {...styles.grid()}>
      <Example defaultValue={5} invalid />
    </div>
  )
}

namespace styles {
  export const grid = style({
    alignItems: 'start',
    display: 'grid',
    gap: '3',
    gridTemplateColumns: 'repeat(auto-fill, minmax(240px, 1fr)) !custom',
    maxWidth: '520px !custom',
  })
}
```

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

### Disabled

Set `disabled` on `NumberField.Root` to make the field unavailable.

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

function Example(
  props: Pick<NumberField.Root.Props, 'defaultValue' | 'disabled' | 'max' | 'min' | 'step'> &
    Pick<NumberField.Group.Props, 'invalid' | 'size'>,
) {
  const { invalid, size, ...root } = props

  return (
    <NumberField.Root {...root}>
      <NumberField.Group invalid={invalid} size={size}>
        <NumberField.Decrement />
        <NumberField.Input aria-label="Quantity" />
        <NumberField.Increment />
      </NumberField.Group>
    </NumberField.Root>
  )
}

export function Demo() {
  return (
    <div {...styles.grid()}>
      <Example defaultValue={5} disabled />
    </div>
  )
}

namespace styles {
  export const grid = style({
    alignItems: 'start',
    display: 'grid',
    gap: '3',
    gridTemplateColumns: 'repeat(auto-fill, minmax(240px, 1fr)) !custom',
    maxWidth: '520px !custom',
  })
}
```

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

## Guidelines

TODO: Write guidelines for NumberField.
