Apply a Word table style
Give a table one of Word's 105 built-in table styles, such as Grid Table 4 or List Table 3, from your code or from an agent.
SuperDoc includes Word's 105 built-in table styles, the ones in Word's Table Design gallery. tables.applyPreset gives a table one of them. In Word, the table uses that named style, and its colors follow the document's theme.
Two operations do the work:
tables.listPresetsfinds a style and returns its preset ID.tables.applyPresetapplies it to a table.
Try it
This Node.js script styles the first table in pricing.docx as Grid Table 4 - Accent 1. Install the Node.js SDK, save the script as table-style.ts, and put a DOCX with a table next to it:
import { SuperDocClient } from '@superdoc/sdk';
const client = new SuperDocClient();
try {
await client.connect();
const doc = await client.open({ doc: './pricing.docx' });
try {
const { blocks } = await doc.blocks.list({ nodeTypes: ['table'] });
const table = blocks[0];
if (!table) throw new Error('pricing.docx has no table.');
const page = await doc.tables.listPresets({ source: 'word', query: 'Grid Table 4' });
console.log(page.items.map((preset) => `${preset.id} ${preset.name}`));
await doc.tables.applyPreset({
nodeId: table.nodeId,
preset: 'word.grid-table-4-accent-1',
styleOptions: { headerRow: true, bandedRows: true, firstColumn: false },
});
const { styleId } = await doc.tables.getProperties({ nodeId: table.nodeId });
console.log('Table style:', styleId);
await doc.save({ out: './pricing.styled.docx', force: true });
} finally {
await doc.close({ discard: true });
}
} finally {
await client.dispose();
}
npx tsx table-style.tsIt prints the seven Grid Table 4 presets, applies one, and prints the table's style ID, GridTable4-Accent1. Open pricing.styled.docx in Word to see the result.
The same calls work in the browser editor, through superdoc.activeEditor.doc, and in the other SDKs:
// Browser
const doc = superdoc.activeEditor?.doc;
await doc?.tables.applyPreset({ nodeId, preset: 'word.list-table-3', styleOptions: { headerRow: true } });# Python
page = document.tables.list_presets({"source": "word", "query": "List Table 3"})
document.tables.apply_preset({"nodeId": node_id, "preset": "word.list-table-3", "styleOptions": {"headerRow": True}})# CLI
superdoc tables list-presets --query "Grid Table 4"
superdoc tables apply-preset --node-id TABLE_ID --preset word.grid-table-4-accent-1 --style-options-json '{"headerRow":true,"bandedRows":true}'In Rust, the calls are tables().list_presets(¶ms) and tables().apply_preset(¶ms) on doc.api().
nodeId identifies the table. Get it from blocks.list({ nodeTypes: ['table'] }), or in the browser from superdoc.ui.tables.getContext().tableNodeId for the table under the cursor. Read the context right before the call, not from a cached copy.
Find a style
Preset IDs follow Word's style names:
| Word style | Preset ID |
|---|---|
| Table Grid | word.table-grid |
| Table Grid Light | word.grid-table-light |
| Plain Table 1 to 5 | word.plain-table-1 to word.plain-table-5 |
| Grid Table 1 Light to Grid Table 7 Colorful | word.grid-table-1-light, -2, -3, -4, -5-dark, -6-colorful, -7-colorful |
| List Table 1 Light to List Table 7 Colorful | word.list-table-1-light, -2, -3, -4, -5-dark, -6-colorful, -7-colorful |
| Accent 1 to 6 of a Grid or List Table | Add -accent-1 to -accent-6, for example word.grid-table-4-accent-1 |
tables.listPresets searches the catalog. It reads no document, so its result is the same for every file:
| Input | Meaning |
|---|---|
source | word for Word's styles, superdoc for SuperDoc's four presets. |
group | plain, grid, list or convenience. |
query | Matches IDs, names and appearance terms, such as Grid Table 4, shading banded rows or horizontal borders. |
limit | 1 to 25. The default is 25. |
offset | Where the page starts. |
The result has items, the filtered total, offset and nextOffset. A page can hold fewer than limit items, so call again with offset: nextOffset until nextOffset is null. Each item has id, name, source, group, accent (1 to 6, or null) and appearance.
To list the table styles a document already contains, call tables.getStyles instead.
Choose a style by its look
Each Word preset describes how it looks in appearance. This is word.grid-table-4-accent-1:
{
"header": {
"treatment": ["shading", "bold", "borders"],
"fill": { "themeColor": "accent1" },
"textColor": { "themeColor": "background1" }
},
"bandedRows": { "effect": "shading", "fill": { "themeColor": "accent1", "tint": "33" } },
"borders": { "layout": "grid", "color": { "themeColor": "accent1", "tint": "99" } }
}| Field | Values |
|---|---|
header.treatment | Any of shading, bold and borders. fill and textColor give the header's colors. |
bandedRows.effect | none, shading, borders or shadingAndBorders. borders adds lines between rows but no fill. |
borders.layout | none, horizontal, outer, outerAndHorizontal or grid. |
baseFill | Present when the whole table has a fill. |
Colors name a theme slot, not a fixed color. accent1 is blue in Word's default theme, and can be green or any other color in a branded document. To get the real color, read styles.getTheme():
- For
text1,background1,text2andbackground2, look upt1,bg1,t2orbg2intheme.colorSchemeMappingto get a slot name. Without a mapping, Word usesdk1,lt1,dk2andlt2. - For
accent1toaccent6, use the mapping's entry when there is one, otherwise the slot with the same name. - Read the slot's hex value from
theme.colorScheme. - Apply
tint(lighter, toward white) orshade(darker, toward black). Each is a hex byte from00toFF, as in Word'sw:themeTintandw:themeShade.
appearance covers the header, the first banded row and the main borders. A property it leaves out is inherited, not white or borderless. Direct formatting on cells and text overrides the style.
Turn table regions on and off
styleOptions matches the checkboxes under Table Style Options in Word:
| Flag | Word checkbox |
|---|---|
headerRow | Header Row |
lastRow | Total Row |
firstColumn | First Column |
lastColumn | Last Column |
bandedRows | Banded Rows |
bandedColumns | Banded Columns |
Send every flag you care about. A flag you leave out keeps its current value. If the table has no flags yet, the ones you leave out get Word's defaults, and Word's default turns First Column on.
To change the flags later without applying the style again, call tables.applyStyle({ nodeId, styleOptions }).
What applying a style changes
- SuperDoc copies Word's definition of the style into the document's
styles.xmland points the table at it, in one edit. - When the document already has the same definition, SuperDoc reuses it.
- When the document has its own, customized version of that style, SuperDoc keeps it and installs Word's version under a new ID, such as
GridTable4-Accent1-Word. Read the ID the table uses withtables.getProperties. - Borders and shading set on the whole table are removed, so the style controls them. Formatting set on individual cells and text stays and overrides the style.
- Applying the same preset again succeeds and changes nothing. Pass
dryRun: trueto check a call without changing the document.
Unknown preset IDs fail with INVALID_INPUT and change nothing.
Collaboration and tracked changes
In a collaboration room, every connected editor receives the style definition and the table change together. Undo and redo work on every peer.
Word presets are direct edits. With changeMode: 'tracked', the call fails with CAPABILITY_UNAVAILABLE and changes nothing.
SuperDoc presets
grid, minimal, striped and accent are SuperDoc's own presets. They write borders, banding and header shading directly onto the table instead of applying a named Word style, so their appearance is null. accentColor sets the color of the accent preset.
Word presets reject accentColor with INVALID_INPUT. For a Word style in a theme color, pick one of its -accent-1 to -accent-6 presets.
Let an agent apply a style
Give the model a custom action on the core preset. The model names a Word style, and the action finds it and applies it:
import { createAgentToolkit, defineAction, type BoundDocApi } from '@superdoc/sdk';
type PresetId = Parameters<BoundDocApi['tables']['applyPreset']>[0]['preset'];
const isListedPreset = (id: string, listed: ReadonlyArray<{ id: string }>): id is PresetId =>
listed.some((item) => item.id === id);
const normalize = (value: string) =>
value
.toLowerCase()
.replace(/[^a-z0-9]+/g, ' ')
.trim();
export const applyTableStyle = defineAction({
name: 'superdoc.apply_table_style',
description:
'Apply a built-in Word table style to a table. Name the style as Word does, for example "Table Grid", ' +
'"Plain Table 2", "List Table 3", or "Grid Table 4 - Accent 1". Accent 1-6 follow the document theme colors.',
input: {
type: 'object',
properties: {
style: { type: 'string', description: 'Word table style name or preset id.' },
tableOrdinal: { type: 'number', description: '1-based table number. Defaults to 1.' },
headerRow: { type: 'boolean', description: 'Format the first row as a header. Defaults to true.' },
bandedRows: { type: 'boolean', description: 'Alternate row formatting. Defaults to true.' },
firstColumn: { type: 'boolean', description: 'Emphasize the first column. Defaults to false.' },
},
required: ['style'],
},
run: async (doc, args) => {
const ordinal = typeof args.tableOrdinal === 'number' ? args.tableOrdinal : 1;
const { blocks } = await doc.blocks.list({ nodeTypes: ['table'] });
const table = blocks[ordinal - 1];
if (!table) throw new Error(`Table ${ordinal} does not exist. The document has ${blocks.length}.`);
const wanted = normalize(String(args.style));
const { items } = await doc.tables.listPresets({ source: 'word', query: String(args.style) });
const preset = items.find((item) => normalize(item.id) === wanted || normalize(item.name) === wanted);
if (!preset || !isListedPreset(preset.id, items)) {
const names = items.map((item) => item.name).join(', ');
throw new Error(`No Word table style is named "${args.style}". Close matches: ${names || 'none'}.`);
}
await doc.tables.applyPreset({
nodeId: table.nodeId,
preset: preset.id,
styleOptions: {
headerRow: args.headerRow !== false,
bandedRows: args.bandedRows !== false,
firstColumn: args.firstColumn === true,
},
});
return { tableOrdinal: ordinal, style: preset.name };
},
});
export const toolkit = await createAgentToolkit({
provider: 'openai',
preset: 'core',
customActions: [applyTableStyle],
});
The model passes a name such as Grid Table 4 - Accent 1. If no style has that name, the action throws an error that lists similar names, when there are any, so the model can try again.
When the request describes a look instead of naming a style, such as "a green header with banded rows", use the full preset. It can read the theme, compare appearance, and apply the best match.
The core preset's built-in style_table action applies SuperDoc's accent look, not a Word style. The MCP server has no action for Word table styles yet.
Limits
- Tracked changes. A Word preset cannot be recorded as a tracked change.
- Built-in styles only. The catalog holds Word's built-in styles. To apply a table style the document already defines, pass its ID from
tables.getStylestotables.applyStyle. No operation creates a new table style. - Appearance.
appearancedescribes the header, the first banded row and the main borders. It does not describe the total row, the first and last columns, or banded columns.
See the reference for tables.listPresets, tables.applyPreset, tables.getProperties, tables.applyStyle, tables.getStyles and styles.getTheme.