From 8cde93831221459b2807aa0c7ea245ea82da766b Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Fri, 26 Jun 2026 16:45:43 -0700 Subject: [PATCH] feat(types): add data_table Block Kit block Add the `data_table` block (`DataTableBlock`) and the `raw_number` cell composition object (`RawNumberElement`) used for numeric, sortable cells. The block is added to the `KnownBlock` union and covered by tsd type tests. Ref: https://docs.slack.dev/reference/block-kit/blocks/data-table-block Co-Authored-By: Claude --- .changeset/data-table-block.md | 5 ++ packages/types/src/block-kit/blocks.ts | 38 ++++++++++++++ .../src/block-kit/composition-objects.ts | 19 +++++++ packages/types/test/blocks.test-d.ts | 52 ++++++++++++++++++- 4 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 .changeset/data-table-block.md diff --git a/.changeset/data-table-block.md b/.changeset/data-table-block.md new file mode 100644 index 000000000..0aa292665 --- /dev/null +++ b/.changeset/data-table-block.md @@ -0,0 +1,5 @@ +--- +"@slack/types": minor +--- + +feat: add `data_table` Block Kit block type (`DataTableBlock`) and the `raw_number` cell composition object (`RawNumberElement`) diff --git a/packages/types/src/block-kit/blocks.ts b/packages/types/src/block-kit/blocks.ts index 365492d93..23e7d6c14 100644 --- a/packages/types/src/block-kit/blocks.ts +++ b/packages/types/src/block-kit/blocks.ts @@ -28,6 +28,7 @@ import type { import type { MrkdwnElement, PlainTextElement, + RawNumberElement, RawTextElement, SlackFileImageObject, TextObject, @@ -60,6 +61,7 @@ export type KnownBlock = | CarouselBlock | ContextBlock | ContextActionsBlock + | DataTableBlock | DividerBlock | FileBlock | HeaderBlock @@ -226,6 +228,42 @@ export interface ContextActionsBlock extends Block { elements: ContextActionsBlockElement[]; } +/** + * A helper union type of all cell types that can be used in a {@link DataTableBlock} row. Cells can be of type + * `raw_text`, `raw_number`, or `rich_text`. Note that `rich_text` cells are not allowed in the header row. + */ +export type DataTableCell = RawTextElement | RawNumberElement | RichTextBlock; + +/** + * @description Displays structured, sortable, and paginated data in a table. + * @see {@link https://docs.slack.dev/reference/block-kit/blocks/data-table-block Data table block reference}. + */ +export interface DataTableBlock extends Block { + /** + * @description The type of block. For a data table block, `type` is always `data_table`. + */ + type: 'data_table'; + /** + * @description An array consisting of table rows, where the first row is the header row. Each row is an array of + * cells of type `raw_text`, `raw_number`, or `rich_text`. Minimum 2 rows (a header and one data row) and maximum 101 + * rows (a header and 100 data rows). Each row must contain the same number of cells, with a minimum of 1 and a maximum + * of 20 columns. The `rich_text` cell type is not allowed in the header row. + */ + rows: DataTableCell[][]; + /** + * @description A description of the table used for the underlying HTML element. + */ + caption: string; + /** + * @description The number of rows to display per page. Minimum 1, maximum 100. Defaults to 5 if not provided. + */ + page_size?: number; + /** + * @description The zero-based index of the column used as the row identifier. Defaults to 0 if not provided. + */ + row_header_column_index?: number; +} + /** * @description Visually separates pieces of info inside of a message. A content divider, like an `
`, to split up * different blocks inside of a message. The divider block is nice and neat, requiring only a `type`. diff --git a/packages/types/src/block-kit/composition-objects.ts b/packages/types/src/block-kit/composition-objects.ts index 886830344..59e607226 100644 --- a/packages/types/src/block-kit/composition-objects.ts +++ b/packages/types/src/block-kit/composition-objects.ts @@ -188,6 +188,25 @@ export interface RawTextElement { text: string; } +/** + * @description Defines an object containing a numeric value and its display text. Used for numeric cells in a + * {@link DataTableBlock}, allowing the column to be sorted numerically. + */ +export interface RawNumberElement { + /** + * @description The formatting to use for this object. + */ + type: 'raw_number'; + /** + * @description The numeric value used for sorting the column. + */ + value: number; + /** + * @description The text used to display the value. The minimum length is 1 character. + */ + text: string; +} + interface BaseConversationFilter { /** * @description Indicates which type of conversations should be included in the list. When this field is provided, any diff --git a/packages/types/test/blocks.test-d.ts b/packages/types/test/blocks.test-d.ts index e154b6c1b..8023d2687 100644 --- a/packages/types/test/blocks.test-d.ts +++ b/packages/types/test/blocks.test-d.ts @@ -1,5 +1,5 @@ import { expectAssignable, expectError } from 'tsd'; -import type { AlertBlock, CardBlock, CarouselBlock, KnownBlock } from '../src/index'; +import type { AlertBlock, CardBlock, CarouselBlock, DataTableBlock, KnownBlock } from '../src/index'; // CardBlock // -- sad path @@ -62,3 +62,53 @@ expectAssignable({ type: 'carousel', elements: [{ type: 'card' }], }); + +// DataTableBlock +// -- sad path +expectError({}); // missing type, rows, and caption +expectError({ type: 'data_table' }); // missing required rows and caption +expectError({ + type: 'data_table', + rows: [[{ type: 'raw_text', text: 'Name' }]], +}); // missing required caption +expectError({ + type: 'data_table', + caption: 'A list of fruit and their quantities', +}); // missing required rows +// -- happy path +expectAssignable({ + type: 'data_table', + caption: 'A list of fruit and their quantities', + rows: [ + [ + { type: 'raw_text', text: 'Fruit' }, + { type: 'raw_text', text: 'Quantity' }, + ], + [ + { type: 'raw_text', text: 'Apples' }, + { type: 'raw_number', value: 12, text: '12' }, + ], + ], +}); +expectAssignable({ + type: 'data_table', + caption: 'A list of users', + block_id: 'users_table', + page_size: 10, + row_header_column_index: 0, + rows: [ + [ + { type: 'raw_text', text: 'User' }, + { type: 'raw_text', text: 'Bio' }, + ], + [ + { type: 'raw_text', text: 'Mark' }, + { type: 'rich_text', elements: [{ type: 'rich_text_section', elements: [{ type: 'text', text: 'Founder' }] }] }, + ], + ], +}); +expectAssignable({ + type: 'data_table', + caption: 'A minimal table', + rows: [[{ type: 'raw_text', text: 'Header' }], [{ type: 'raw_text', text: 'Value' }]], +});