{
  "$id": "https://tablekit.amitpatjoshi.com/schema/v1.json",
  "title": "tablekit TableSchema v1",
  "description": "Declarative config for <DataTable schema={…} /> from @tablekit/react.",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "$schema": {
      "type": "string"
    },
    "version": {
      "default": 1,
      "type": "number",
      "const": 1
    },
    "title": {
      "description": "Shown in the toolbar and used as the accessible name.",
      "type": "string"
    },
    "description": {
      "type": "string"
    },
    "rowId": {
      "description": "Row field used as a stable id. Default `id`.",
      "type": "string"
    },
    "columns": {
      "minItems": 1,
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "field": {
            "type": "string",
            "minLength": 1,
            "description": "Row property to read. Dot paths are supported: `customer.name`."
          },
          "header": {
            "type": "string",
            "description": "Visible column label."
          },
          "type": {
            "default": "text",
            "description": "Controls formatting, alignment, sorting and the default filter.",
            "type": "string",
            "enum": [
              "text",
              "number",
              "currency",
              "date",
              "badge",
              "avatar",
              "link",
              "boolean",
              "actions",
              "button"
            ]
          },
          "id": {
            "description": "Defaults to `field`. Must be unique.",
            "type": "string"
          },
          "sortable": {
            "description": "Default true (false for `actions`).",
            "type": "boolean"
          },
          "filter": {
            "description": "Column filter UI. Defaults: badge/boolean → select, number/currency/date → range, others → none.",
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "text",
                  "select",
                  "range"
                ]
              },
              {
                "type": "boolean",
                "const": false
              }
            ]
          },
          "searchable": {
            "description": "Include in global search. Default true.",
            "type": "boolean"
          },
          "hideable": {
            "description": "Show in the column visibility menu. Default true.",
            "type": "boolean"
          },
          "hidden": {
            "description": "Start hidden.",
            "type": "boolean"
          },
          "width": {
            "description": "Initial width in px.",
            "type": "integer",
            "exclusiveMinimum": 0,
            "maximum": 9007199254740991
          },
          "minWidth": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "maximum": 9007199254740991
          },
          "maxWidth": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "maximum": 9007199254740991
          },
          "pinned": {
            "description": "Initially pinned to the start edge (sticky when scrolling horizontally). Users can change it when features.columnPinning is on.",
            "type": "boolean"
          },
          "priority": {
            "description": "1 = always visible … 5 = first to hide on narrow screens (responsive=priority).",
            "type": "integer",
            "minimum": 1,
            "maximum": 5
          },
          "align": {
            "description": "Numbers default to end.",
            "type": "string",
            "enum": [
              "start",
              "center",
              "end"
            ]
          },
          "format": {
            "type": "object",
            "properties": {
              "locale": {
                "description": "BCP 47, e.g. `en-US`, `de-DE`.",
                "type": "string"
              },
              "currency": {
                "description": "ISO 4217 code, e.g. `USD`.",
                "type": "string",
                "minLength": 3,
                "maxLength": 3
              },
              "decimals": {
                "type": "integer",
                "minimum": 0,
                "maximum": 8
              },
              "notation": {
                "type": "string",
                "enum": [
                  "standard",
                  "compact"
                ]
              },
              "style": {
                "type": "string",
                "enum": [
                  "decimal",
                  "percent"
                ]
              },
              "unit": {
                "description": "Intl unit, e.g. `kilobyte`, `percent`.",
                "type": "string"
              },
              "dateStyle": {
                "type": "string",
                "enum": [
                  "short",
                  "medium",
                  "long",
                  "relative"
                ]
              },
              "timeStyle": {
                "type": "string",
                "enum": [
                  "short",
                  "medium"
                ]
              },
              "trueLabel": {
                "type": "string"
              },
              "falseLabel": {
                "type": "string"
              },
              "prefix": {
                "type": "string"
              },
              "suffix": {
                "type": "string"
              }
            },
            "additionalProperties": false
          },
          "badge": {
            "description": "Only for type=badge.",
            "type": "object",
            "properties": {
              "tones": {
                "description": "Value → tone, e.g. { \"paid\": \"success\", \"overdue\": \"danger\" }.",
                "type": "object",
                "propertyNames": {
                  "type": "string"
                },
                "additionalProperties": {
                  "type": "string",
                  "enum": [
                    "neutral",
                    "info",
                    "success",
                    "warning",
                    "danger",
                    "accent"
                  ],
                  "description": "Semantic color. Maps to --tk-tone-* tokens; never a raw color."
                }
              },
              "labels": {
                "description": "Value → display label.",
                "type": "object",
                "propertyNames": {
                  "type": "string"
                },
                "additionalProperties": {
                  "type": "string"
                }
              },
              "defaultTone": {
                "type": "string",
                "enum": [
                  "neutral",
                  "info",
                  "success",
                  "warning",
                  "danger",
                  "accent"
                ],
                "description": "Semantic color. Maps to --tk-tone-* tokens; never a raw color."
              },
              "fill": {
                "description": "Tinted background. Default true. false + stroke = outline badge.",
                "type": "boolean"
              },
              "stroke": {
                "description": "1px border in the tone's colour. Default false. Combine with fill for a tinted, bordered badge.",
                "type": "boolean"
              },
              "indicator": {
                "description": "Leading mark. dot (default; \"icon\" when `icons` is set), icon = icon + label, icon-only = icon with the label as tooltip and screen-reader text, none = label only.",
                "type": "string",
                "enum": [
                  "dot",
                  "icon",
                  "icon-only",
                  "none"
                ]
              },
              "icons": {
                "description": "Value → Lucide icon name, e.g. { \"settled\": \"circle-check\", \"processing\": \"loader\" }. Values without one use their tone's default icon.",
                "type": "object",
                "propertyNames": {
                  "type": "string"
                },
                "additionalProperties": {
                  "type": "string",
                  "enum": [
                    "circle-check",
                    "check",
                    "circle-x",
                    "x",
                    "triangle-alert",
                    "circle-alert",
                    "info",
                    "circle-dashed",
                    "circle",
                    "circle-dot",
                    "circle-pause",
                    "clock",
                    "hourglass",
                    "loader",
                    "refresh-cw",
                    "ban",
                    "lock",
                    "shield-check",
                    "arrow-up",
                    "arrow-down",
                    "arrow-right",
                    "undo-2",
                    "send",
                    "truck",
                    "star",
                    "zap",
                    "sparkles",
                    "eye"
                  ]
                }
              }
            },
            "additionalProperties": false
          },
          "avatar": {
            "description": "Only for type=avatar. `field` is the display name.",
            "type": "object",
            "properties": {
              "imageField": {
                "description": "Row field holding the image URL.",
                "type": "string"
              },
              "imageDarkField": {
                "description": "Row field holding a dark-theme variant of the image (e.g. a light logo for dark backgrounds). Shown instead of imageField when the table is dark.",
                "type": "string"
              },
              "subtitleField": {
                "description": "Row field shown under the name.",
                "type": "string"
              },
              "logo": {
                "description": "Render the image as a brand logo (bank, merchant, provider) instead of a person: inline = 16px compact mark centred on the name's first line, no container; circle = mark centred in a filled circle.",
                "type": "string",
                "enum": [
                  "inline",
                  "circle"
                ]
              },
              "logoFill": {
                "description": "Fill behind logo=circle. Default neutral.",
                "type": "string",
                "enum": [
                  "neutral",
                  "accent"
                ]
              }
            },
            "additionalProperties": false
          },
          "link": {
            "description": "Only for type=link.",
            "type": "object",
            "properties": {
              "hrefField": {
                "description": "Row field holding the URL.",
                "type": "string"
              },
              "hrefTemplate": {
                "description": "URL with {field} placeholders, e.g. `/orders/{id}`.",
                "type": "string"
              },
              "external": {
                "description": "Open in a new tab with rel=noopener.",
                "type": "boolean"
              }
            },
            "additionalProperties": false
          },
          "actions": {
            "description": "Only for type=actions. Row menu items.",
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "description": "Stable id passed to onAction / onBulkAction."
                },
                "label": {
                  "type": "string"
                },
                "tone": {
                  "description": "`danger` for destructive actions.",
                  "type": "string",
                  "enum": [
                    "neutral",
                    "danger"
                  ]
                },
                "icon": {
                  "description": "Lucide icon name. Required for every action when actionsDisplay is inline.",
                  "type": "string",
                  "enum": [
                    "eye",
                    "pencil",
                    "copy",
                    "download",
                    "upload",
                    "share-2",
                    "send",
                    "external-link",
                    "refresh-cw",
                    "undo-2",
                    "archive",
                    "trash-2",
                    "ban",
                    "lock",
                    "unlock",
                    "check",
                    "x",
                    "user-plus",
                    "mail",
                    "receipt",
                    "flag",
                    "star"
                  ]
                },
                "disabled": {
                  "description": "Shown but not selectable.",
                  "type": "boolean"
                },
                "separator": {
                  "description": "Draw a divider before this item (menu only).",
                  "type": "boolean"
                },
                "when": {
                  "description": "Only show for rows where row[field] is one of `in`, e.g. { \"field\": \"status\", \"in\": [\"paid\"] }.",
                  "type": "object",
                  "properties": {
                    "field": {
                      "type": "string"
                    },
                    "in": {
                      "minItems": 1,
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  },
                  "required": [
                    "field",
                    "in"
                  ],
                  "additionalProperties": false
                }
              },
              "required": [
                "id",
                "label"
              ],
              "additionalProperties": false
            }
          },
          "actionsDisplay": {
            "description": "Only for type=actions. menu (default) = ⋯ menu; inline = icon buttons (every action needs an icon). For one clear call to action per row, use a type=button column instead.",
            "type": "string",
            "enum": [
              "menu",
              "inline"
            ]
          },
          "button": {
            "description": "Only for type=button: a single button inside the cell (e.g. Pay, Download, Retry).",
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Action id passed to onAction(id, row)."
              },
              "label": {
                "description": "Button text. Defaults to the cell value.",
                "type": "string"
              },
              "variant": {
                "description": "secondary (default, outlined) · primary (accent fill) · ghost (text only).",
                "type": "string",
                "enum": [
                  "secondary",
                  "primary",
                  "ghost"
                ]
              },
              "tone": {
                "type": "string",
                "enum": [
                  "neutral",
                  "danger"
                ]
              },
              "icon": {
                "description": "Leading Lucide icon.",
                "type": "string",
                "enum": [
                  "eye",
                  "pencil",
                  "copy",
                  "download",
                  "upload",
                  "share-2",
                  "send",
                  "external-link",
                  "refresh-cw",
                  "undo-2",
                  "archive",
                  "trash-2",
                  "ban",
                  "lock",
                  "unlock",
                  "check",
                  "x",
                  "user-plus",
                  "mail",
                  "receipt",
                  "flag",
                  "star"
                ]
              },
              "when": {
                "description": "Only render the button on rows where row[field] is one of `in`; other rows show nothing.",
                "type": "object",
                "properties": {
                  "field": {
                    "type": "string"
                  },
                  "in": {
                    "minItems": 1,
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                },
                "required": [
                  "field",
                  "in"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "id"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "field",
          "header"
        ],
        "additionalProperties": false
      }
    },
    "features": {
      "default": {},
      "type": "object",
      "properties": {
        "search": {
          "default": true,
          "description": "Global search box.",
          "type": "boolean"
        },
        "columnFilters": {
          "default": true,
          "type": "boolean"
        },
        "sorting": {
          "default": true,
          "type": "boolean"
        },
        "multiSort": {
          "default": true,
          "type": "boolean"
        },
        "pagination": {
          "default": true,
          "type": "boolean"
        },
        "pageSize": {
          "default": 10,
          "type": "integer",
          "exclusiveMinimum": 0,
          "maximum": 9007199254740991
        },
        "pageSizeOptions": {
          "default": [
            10,
            25,
            50,
            100
          ],
          "type": "array",
          "items": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "maximum": 9007199254740991
          }
        },
        "selection": {
          "default": "none",
          "type": "string",
          "enum": [
            "none",
            "single",
            "multi"
          ]
        },
        "columnVisibility": {
          "default": true,
          "type": "boolean"
        },
        "columnResize": {
          "default": true,
          "type": "boolean"
        },
        "columnReorder": {
          "default": true,
          "description": "Users can reorder columns from the column menu (drag or Alt+Arrow keys).",
          "type": "boolean"
        },
        "columnPinning": {
          "default": true,
          "description": "Users can pin columns to the start edge from the column menu. `column.pinned` sets the initial state.",
          "type": "boolean"
        },
        "stickyHeader": {
          "default": true,
          "type": "boolean"
        }
      },
      "additionalProperties": false
    },
    "appearance": {
      "default": {},
      "type": "object",
      "properties": {
        "density": {
          "default": "default",
          "type": "string",
          "enum": [
            "compact",
            "default",
            "comfortable"
          ]
        },
        "variant": {
          "default": "plain",
          "type": "string",
          "enum": [
            "plain",
            "zebra",
            "bordered"
          ]
        },
        "responsive": {
          "default": "stack",
          "description": "Narrow-screen behavior. stack = cards, scroll = horizontal scroll, priority = drop low-priority columns.",
          "type": "string",
          "enum": [
            "stack",
            "scroll",
            "priority"
          ]
        },
        "stackBelow": {
          "default": 640,
          "description": "Container width (px) below which `stack` switches to cards.",
          "type": "integer",
          "exclusiveMinimum": 0,
          "maximum": 9007199254740991
        }
      },
      "additionalProperties": false
    },
    "initialState": {
      "type": "object",
      "properties": {
        "sort": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "desc": {
                "default": false,
                "type": "boolean"
              }
            },
            "required": [
              "id"
            ],
            "additionalProperties": false
          }
        },
        "search": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "bulkActions": {
      "description": "Shown in the selection bar when rows are selected. Requires selection=multi.",
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Stable id passed to onAction / onBulkAction."
          },
          "label": {
            "type": "string"
          },
          "tone": {
            "description": "`danger` for destructive actions.",
            "type": "string",
            "enum": [
              "neutral",
              "danger"
            ]
          },
          "icon": {
            "description": "Lucide icon name. Required for every action when actionsDisplay is inline.",
            "type": "string",
            "enum": [
              "eye",
              "pencil",
              "copy",
              "download",
              "upload",
              "share-2",
              "send",
              "external-link",
              "refresh-cw",
              "undo-2",
              "archive",
              "trash-2",
              "ban",
              "lock",
              "unlock",
              "check",
              "x",
              "user-plus",
              "mail",
              "receipt",
              "flag",
              "star"
            ]
          },
          "disabled": {
            "description": "Shown but not selectable.",
            "type": "boolean"
          },
          "separator": {
            "description": "Draw a divider before this item (menu only).",
            "type": "boolean"
          },
          "when": {
            "description": "Only show for rows where row[field] is one of `in`, e.g. { \"field\": \"status\", \"in\": [\"paid\"] }.",
            "type": "object",
            "properties": {
              "field": {
                "type": "string"
              },
              "in": {
                "minItems": 1,
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            },
            "required": [
              "field",
              "in"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "id",
          "label"
        ],
        "additionalProperties": false
      }
    },
    "emptyState": {
      "type": "object",
      "properties": {
        "title": {
          "type": "string"
        },
        "description": {
          "type": "string"
        }
      },
      "required": [
        "title"
      ],
      "additionalProperties": false
    }
  },
  "required": [
    "columns"
  ],
  "additionalProperties": false
}
