> ## Documentation Index
> Fetch the complete documentation index at: https://anvil.servicetitan.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Number Edit Mode

> Guide for adopting the new number edit mode for editable DataTable cells.

export const VersionStatus = ({version}) => {
  const isUnreleased = version === "unreleased";
  return <Badge color={isUnreleased ? "orange" : "green"}>
      {isUnreleased ? "Unreleased" : `v${version}`}
    </Badge>;
};

<VersionStatus version="2.1.0" />

<Note>
  This guide covers changes to the **beta** DataTable component. These APIs may continue to evolve before the stable release.
</Note>

## Overview

This guide continues the work started in [Column Types and EditConfig](/docs/web/components/data-table/beta-changes/column-types), which introduced the `editConfig` property and the `text`, `select`, and `multiselect` edit modes. That guide also outlined how the `editConfig` structure supports new edit modes with mode-specific options — the number edit mode is the first to use this pattern.

The DataTable now supports a dedicated **number** edit mode for inline editing of numeric cell values:

* **`editConfig.mode: "number"`** - Renders a formatted number input with validation, decimal precision, and keyboard increment/decrement
* **Number-specific options** - Configure `minValue`, `maxValue`, `step`, and fraction digit precision directly on `editConfig`

Previously, editable text cells silently coerced numeric values to strings. The new number edit mode handles numeric data natively, preserving type safety and providing a better editing experience.

## Design Rationale

### Why a dedicated number mode?

The text edit mode previously accepted number values by converting them to strings:

```tsx theme={null}
// Before: Number values silently coerced to strings
createColumn("amount", {
  headerLabel: "Amount",
  editConfig: {
    mode: "text",
    onChange: (value, rowId) => {
      // value is a string — requires manual parsing
      updateAmount(parseFloat(value), rowId);
    },
  },
});
```

This approach had several problems:

* Values lost their numeric type, requiring manual parsing in `onChange`
* No input validation for numeric constraints like min/max
* No keyboard increment/decrement support
* No decimal precision formatting

The new number mode addresses all of these:

```tsx theme={null}
// After: Purpose-built number editing
createColumn("amount", {
  headerLabel: "Amount",
  type: "currency",
  editConfig: {
    mode: "number",
    minValue: 0,
    maxValue: 100000,
    step: 0.01,
    maximumFractionDigits: 2,
    onChange: (value, rowId) => {
      // value is number | null — no parsing needed
      updateAmount(value, rowId);
    },
  },
});
```

### Relationship between `type` and `editConfig`

The `type` property controls how a value is **displayed** when the cell is not being edited. The `editConfig` controls the **editing** behavior. These are independent concerns:

```tsx theme={null}
// Display as currency, edit as number
createColumn("amount", {
  headerLabel: "Amount",
  type: "currency",         // Formats display as "$1,234.56"
  editConfig: {
    mode: "number",         // Edits with a number input
    minimumFractionDigits: 2,
    onChange: handleChange,
  },
});
```

## Number Edit Options Reference

Number-specific options are set directly on the `editConfig` object alongside `mode` and `onChange`. All options are optional.

| Option                  | Type     | Description                                       |
| ----------------------- | -------- | ------------------------------------------------- |
| `minValue`              | `number` | Minimum allowed value                             |
| `maxValue`              | `number` | Maximum allowed value                             |
| `step`                  | `number` | Increment/decrement step for arrow key navigation |
| `minimumFractionDigits` | `number` | Minimum decimal places displayed                  |
| `maximumFractionDigits` | `number` | Maximum decimal places allowed                    |

These options match the [`NumberField`](/docs/web/components/number-field/code) component configuration.

### Basic number editing

```tsx theme={null}
createColumn("quantity", {
  headerLabel: "Quantity",
  type: "number",
  editConfig: {
    mode: "number",
    minValue: 0,
    step: 1,
    onChange: (value, rowId) => updateQuantity(value, rowId),
  },
});
```

### Currency editing with decimal precision

```tsx theme={null}
createColumn("amount", {
  headerLabel: "Amount",
  type: "currency",
  editConfig: {
    mode: "number",
    minValue: 0,
    maxValue: 100000,
    step: 0.01,
    maximumFractionDigits: 2,
    minimumFractionDigits: 2,
    onChange: (value, rowId) => updateAmount(value, rowId),
  },
});
```

## Migration Guide

### Numeric columns using text edit mode

If you were using `editMode: "text"` or `editConfig.mode: "text"` for numeric data, switch to number mode:

```tsx theme={null}
// Before: Text mode with manual number handling
createColumn("amount", {
  headerLabel: "Amount",
  editMode: "text",
  onChange: (value, rowId) => {
    const parsed = parseFloat(value);
    if (!isNaN(parsed)) updateAmount(parsed, rowId);
  },
});

// After: Number mode with native number handling
createColumn("amount", {
  headerLabel: "Amount",
  type: "currency",
  editConfig: {
    mode: "number",
    minValue: 0,
    maximumFractionDigits: 2,
    onChange: (value, rowId) => updateAmount(value ?? 0, rowId),
  },
});
```

### Numeric columns using editConfig text mode

```tsx theme={null}
// Before: editConfig text mode for numbers
createColumn("price", {
  headerLabel: "Price",
  editConfig: {
    mode: "text",
    onChange: (value, rowId) => updatePrice(Number(value), rowId),
  },
});

// After: editConfig number mode
createColumn("price", {
  headerLabel: "Price",
  type: "currency",
  editConfig: {
    mode: "number",
    step: 0.01,
    minimumFractionDigits: 2,
    maximumFractionDigits: 2,
    onChange: (value, rowId) => updatePrice(value ?? 0, rowId),
  },
});
```

## Breaking Changes

<Warning>
  The text edit mode no longer coerces numeric values to strings. Columns with numeric data using text edit mode will render as read-only and log a warning.
</Warning>

The following change is **breaking**:

* **Text edit mode no longer accepts `number` values** - Previously, a cell with `mode: "text"` and a numeric value would silently convert the number to a string. Now, the cell falls back to a read-only state and logs a console warning directing you to use `mode: "number"` instead.

### Why breaking?

Since DataTable is a beta component, we opted to remove the implicit coercion rather than maintain a deprecation path. The coercion masked type mismatches and produced a suboptimal editing experience for numeric data. The new number edit mode is the correct replacement.

## New Exports

The following types are now exported from `@servicetitan/anvil2`:

* `NumberEditConfig` - Edit configuration type for `mode: "number"` columns
