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

# Data validation

> Constrain what people can enter into a range

Validation turns a spreadsheet into a form. It restricts what a cell accepts and explains the rule when someone gets it wrong, which is worth doing on any file you send out to be filled in.

All three rule types share the same range keys and error keys, and differ only in what they check.

<ParamField path="start_row" type="int" required>First row of the range.</ParamField>
<ParamField path="start_col" type="int" required>First column.</ParamField>
<ParamField path="end_row" type="int" required>Last row.</ParamField>
<ParamField path="end_col" type="int" required>Last column.</ParamField>
<ParamField path="error_title" type="str">Heading of the rejection dialog.</ParamField>
<ParamField path="error_message" type="str">Body text. Say what is allowed, not just that the entry was wrong.</ParamField>

## Dropdown lists

<ParamField path="type" type="&#x22;list&#x22;" required />

<ParamField path="items" type="list[str]" required>The permitted values.</ParamField>
<ParamField path="show_dropdown" type="bool">Show the arrow. Leave it on unless you want the constraint hidden.</ParamField>

```python theme={null}
data_validations=[{
    "start_row": 2, "start_col": 0,
    "end_row": 100, "end_col": 0,
    "type": "list",
    "items": ["Active", "Pending", "Closed"],
    "show_dropdown": True,
    "error_title": "Invalid status",
    "error_message": "Choose Active, Pending or Closed.",
}]
```

## Numeric ranges

<ParamField path="type" type="&#x22;whole_number&#x22; | &#x22;decimal&#x22;" required>
  `whole_number` rejects anything with a fractional part. `decimal` allows it.
</ParamField>

<ParamField path="min" type="float" required>Lower bound, inclusive.</ParamField>
<ParamField path="max" type="float" required>Upper bound, inclusive.</ParamField>

```python theme={null}
data_validations=[{
    "start_row": 2, "start_col": 1,
    "end_row": 100, "end_col": 1,
    "type": "whole_number",
    "min": 1, "max": 100,
    "error_title": "Out of range",
    "error_message": "Enter a whole number between 1 and 100.",
}]
```

## Text length

<ParamField path="type" type="&#x22;text_length&#x22;" required />

<ParamField path="min" type="int" required>Fewest characters.</ParamField>
<ParamField path="max" type="int" required>Most characters.</ParamField>

```python theme={null}
data_validations=[{
    "start_row": 2, "start_col": 0,
    "end_row": 100, "end_col": 0,
    "type": "text_length",
    "min": 3, "max": 20,
    "error_title": "Invalid username",
    "error_message": "Usernames are 3 to 20 characters.",
}]
```

## Practical notes

<AccordionGroup>
  <Accordion title="Validate past your data" icon="arrows-down-to-line">
    Apply the rule well beyond the last populated row, to row 100 or 1000, so it still holds when someone adds entries.
  </Accordion>

  <Accordion title="Validation isn't security" icon="lock-open">
    Rules apply to typing. Pasting into a validated cell can bypass them, and any recipient can delete the rule. Treat it as guidance and validate again when the file comes back.
  </Accordion>

  <Accordion title="Write useful messages" icon="comment">
    "Invalid entry" tells nobody anything. Name the permitted values or the bounds.
  </Accordion>
</AccordionGroup>
