I'm trying to allow users to paste (relatively) simple tables into Gutenberg. The editor converts the raw HTML fine but strips out any attributes/classes. For the most part this is good - I want to ensure the markup is clean - but it strips out the colspan
and rowspan
attributes too.
Looking into the table block in the Gutenberg repo on GitHub and block filters in the Guenberg Handbook on wordpress, I've put together the following:
const { getPhrasingContentSchema } = wp.blocks;
// Partially defines what's allowed in a table when pasted.
// Copied from the core table block file in the Gutenberg repo.
const tableContentPasteSchema = {
tr: {
children: {
th: {
children: getPhrasingContentSchema(),
},
td: {
children: getPhrasingContentSchema(),
// This is the only new part in the schema
attributes: [ 'colspan', 'rowspan'],
},
},
},
};
// Partially defines what's allowed in a table when pasted.
// Copied from the core table block file in the Gutenberg repo.
const tablePasteSchema = {
table: {
children: {
thead: {
children: tableContentPasteSchema,
},
tfoot: {
children: tableContentPasteSchema,
},
tbody: {
children: tableContentPasteSchema,
},
},
},
};
// Overloads the table block transforms setting
function addTableBlockSpanAttributes( settings, name ) {
if ( name !== 'core/table' ) {
return settings;
}
return lodash.assign({}, settings, {
transforms: {
from: [
{
type: 'raw',
selector: 'table',
schema: tableSchema,
},
],
},
});
}
wp.hooks.addFilter(
'blocks.registerBlockType',
'my-plugin/transforms/table-block',
addTableBlockSpanAttributes
);
(Code based on example here: )
This all seems to be correct as far as I can tell, but any colspan/rowspans are stripped when pasted in. In addition, manually editing the block in the post HTML causes a block error which can only be resolved by removing the colspan/rowspan attribute.
It's worth noting that if I use the same code but allow colspan
on a <span>
inside the <td>
that works absolutely fine (despite <span colspan="2">
not being valid HTML).
What am I doing wrong? Is there another approach to overloading the core/table
block's allowed attributes? Is there something else in core that's prohibiting <td>
attributes?
I'm trying to allow users to paste (relatively) simple tables into Gutenberg. The editor converts the raw HTML fine but strips out any attributes/classes. For the most part this is good - I want to ensure the markup is clean - but it strips out the colspan
and rowspan
attributes too.
Looking into the table block in the Gutenberg repo on GitHub and block filters in the Guenberg Handbook on wordpress.org, I've put together the following:
const { getPhrasingContentSchema } = wp.blocks;
// Partially defines what's allowed in a table when pasted.
// Copied from the core table block file in the Gutenberg repo.
const tableContentPasteSchema = {
tr: {
children: {
th: {
children: getPhrasingContentSchema(),
},
td: {
children: getPhrasingContentSchema(),
// This is the only new part in the schema
attributes: [ 'colspan', 'rowspan'],
},
},
},
};
// Partially defines what's allowed in a table when pasted.
// Copied from the core table block file in the Gutenberg repo.
const tablePasteSchema = {
table: {
children: {
thead: {
children: tableContentPasteSchema,
},
tfoot: {
children: tableContentPasteSchema,
},
tbody: {
children: tableContentPasteSchema,
},
},
},
};
// Overloads the table block transforms setting
function addTableBlockSpanAttributes( settings, name ) {
if ( name !== 'core/table' ) {
return settings;
}
return lodash.assign({}, settings, {
transforms: {
from: [
{
type: 'raw',
selector: 'table',
schema: tableSchema,
},
],
},
});
}
wp.hooks.addFilter(
'blocks.registerBlockType',
'my-plugin/transforms/table-block',
addTableBlockSpanAttributes
);
(Code based on example here: https://wordpress.org/gutenberg/handbook/designers-developers/developers/filters/block-filters/#blocks-registerblocktype)
This all seems to be correct as far as I can tell, but any colspan/rowspans are stripped when pasted in. In addition, manually editing the block in the post HTML causes a block error which can only be resolved by removing the colspan/rowspan attribute.
It's worth noting that if I use the same code but allow colspan
on a <span>
inside the <td>
that works absolutely fine (despite <span colspan="2">
not being valid HTML).
What am I doing wrong? Is there another approach to overloading the core/table
block's allowed attributes? Is there something else in core that's prohibiting <td>
attributes?
The issue arises because Gutenberg’s table block enforces strict schema validation. Even if you adjust the schema for pasting HTML, the saved attributes for <td>
or <th>
elements (like colspan
and rowspan
) are also validated against the block's save and edit logic. If the attributes aren’t explicitly allowed in the block's registration, Gutenberg will strip them out, leading to errors.
To resolve this and allow colspan
and rowspan
attributes on table cells, you’ll need to modify the schema and ensure the attributes are preserved during the block's save and edit processes. Here’s how you can fix it:
Solution: Modify the Core Table Block
This solution involves extending the core table
block's behavior to include support for colspan
and rowspan
.
td
and th
ElementsAdjust the schema so that colspan
and rowspan
are allowed for td
and th
.
const { assign } = lodash;
const { getPhrasingContentSchema } = wp.blocks;
const tableContentSchema = {
tr: {
children: {
th: {
children: getPhrasingContentSchema(),
attributes: [ 'colspan', 'rowspan' ], // Allow colspan and rowspan on <th>
},
td: {
children: getPhrasingContentSchema(),
attributes: [ 'colspan', 'rowspan' ], // Allow colspan and rowspan on <td>
},
},
},
};
const tableSchema = {
table: {
children: {
thead: {
children: tableContentSchema,
},
tfoot: {
children: tableContentSchema,
},
tbody: {
children: tableContentSchema,
},
},
},
};
transforms
to Use Your SchemaHook into the block registration process and replace the transforms.from
logic with your schema.
function addTableBlockSpanAttributes( settings, name ) {
if ( name !== 'core/table' ) {
return settings;
}
return assign({}, settings, {
transforms: {
from: [
{
type: 'raw',
selector: 'table',
schema: tableSchema,
},
],
},
});
}
wp.hooks.addFilter(
'blocks.registerBlockType',
'my-plugin/transforms/table-block',
addTableBlockSpanAttributes
);
colspan
and rowspan
Extend the core/table
block to save and recognize these attributes.
wp.hooks.addFilter(
'blocks.getSaveContent.extraProps',
'my-plugin/table-cell-attributes',
( extraProps, blockType, attributes ) => {
if ( blockType.name === 'core/table' ) {
// Ensure colspan and rowspan are preserved
if ( attributes.colspan ) {
extraProps.colspan = attributes.colspan;
}
if ( attributes.rowspan ) {
extraProps.rowspan = attributes.rowspan;
}
}
return extraProps;
}
);
Update the save
logic of the table block to ensure the colspan
and rowspan
attributes are saved properly. You can accomplish this by extending the table cell rendering logic.
Test Your Changes
Paste a Table:
<td colspan="2">
or <th rowspan="3">
into the block editor.Edit HTML:
colspan
or rowspan
.Why <span>
Worked?
Gutenberg is less restrictive with inline elements like <span>
because they aren't part of the default table
block schema. By explicitly modifying the table schema, the same flexibility can be applied to <td>
and <th>
.
Additional Notes
colspan
and rowspan
support are added natively, this custom logic may no longer be needed.