diff --git a/.changeset/data-table-block.md b/.changeset/data-table-block.md
new file mode 100644
index 000000000..7b6f6b733
--- /dev/null
+++ b/.changeset/data-table-block.md
@@ -0,0 +1,5 @@
+---
+"@slack/types": minor
+---
+
+feat: add the [`data_table`](https://docs.slack.dev/reference/block-kit/blocks/data-table-block) Block Kit block type (`DataTableBlock`)
diff --git a/packages/types/src/block-kit/blocks.ts b/packages/types/src/block-kit/blocks.ts
index 60ab5166c..20cd9561c 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,
@@ -61,6 +62,7 @@ export type KnownBlock =
| ContainerBlock
| ContextBlock
| ContextActionsBlock
+ | DataTableBlock
| DividerBlock
| FileBlock
| HeaderBlock
@@ -289,6 +291,33 @@ export interface ContextActionsBlock extends Block {
elements: ContextActionsBlockElement[];
}
+/**
+ * @description Displays rich tables that support pagination, sorting, filtering, and interactivity.
+ * @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.
+ */
+ rows: (RawTextElement | RawNumberElement | RichTextBlock)[][];
+ /**
+ * @description A caption for the table; used as the value for the HTML caption element.
+ */
+ caption: string;
+ /**
+ * @description Number of rows per page. Min `1`, Max `100`. Defaults to `5` if omitted.
+ */
+ page_size?: number;
+ /**
+ * @description The 0-based index of the column that uniquely identifies each row (the row header). This column is treated as the row's primary identifier for screen readers. Defaults to `0` if omitted.
+ */
+ 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..b36d1cf50 100644
--- a/packages/types/src/block-kit/composition-objects.ts
+++ b/packages/types/src/block-kit/composition-objects.ts
@@ -173,6 +173,24 @@ export interface MrkdwnElement {
verbatim?: boolean;
}
+/**
+ * @description Defines an object containing a numeric value.
+ */
+export interface RawNumberElement {
+ /**
+ * @description The formatting to use for this numeric object.
+ */
+ type: 'raw_number';
+ /**
+ * @description The numeric value.
+ */
+ value: number;
+ /**
+ * @description The text used to display the value. The minimum length is 1 character.
+ */
+ text: string;
+}
+
/**
* @description Defines an object containing some text.
* @see {@link https://docs.slack.dev/reference/block-kit/composition-objects/text-object Text object reference}.
diff --git a/packages/types/test/blocks.test-d.ts b/packages/types/test/blocks.test-d.ts
index 3169703e5..421941b23 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, ContainerBlock, KnownBlock } from '../src/index';
+import type { AlertBlock, CardBlock, CarouselBlock, ContainerBlock, DataTableBlock, KnownBlock } from '../src/index';
// CardBlock
// -- sad path
@@ -102,3 +102,53 @@ expectAssignable({
title: { type: 'plain_text', text: 'Known' },
child_blocks: [{ type: 'divider' }],
});
+
+// 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' }]],
+});