Wrap the Gutenberg Table Block with Bootstrap Classes Using render_block Filter

Gutenberg’s core Table block renders a plain <figure> wrapping a <table> — functional, but with no responsive overflow handling and no Bootstrap utility classes. On a theme that uses Bootstrap, this means tables overflow their container on small screens and lack the visual styling (striped rows, dark header) that the rest of the UI uses. The render_block filter runs on the final HTML output of every block before it reaches the browser, receiving both the rendered HTML string and the block’s parsed attributes array. This makes it the correct place to inject wrapping markup, add CSS classes, or transform the rendered output of any block — without modifying Gutenberg’s JavaScript or saving different markup to the database. The transformation runs only on the front end, so the editor preview is unaffected.

Problem: Your Bootstrap-based theme needs Gutenberg's Table block to render as a Bootstrap responsive table: the <table> should have class="table table-striped", the <thead> should have class="table-dark", and the whole table should be wrapped in <div class="table-responsive"> — without touching the block editor UI or changing what is saved to the database.

Solution: Use the render_block filter to intercept the core/table block's HTML output, extract the inner <table> from its <figure> wrapper using a regex, add Bootstrap classes to <table> and <thead>, and wrap the result in <div class="table-responsive">.

<?php
add_filter( 'render_block', 'wrap_table_block_bootstrap', 10, 2 );

function wrap_table_block_bootstrap( string $block_content, array $block ): string {
    if ( 'core/table' !== $block['blockName'] ) {
        return $block_content;
    }

    // Extract inner content from the <figure> wrapper that Gutenberg adds
    preg_match( '/<figure[^>]*>(.*?)<\/figure>/s', $block_content, $match );

    if ( ! $match ) {
        // No figure found — wrap whatever is there and return
        return '<div class="table-responsive">' . $block_content . '</div>';
    }

    $inner = $match[1];

    // Add Bootstrap classes to <table> and <thead>
    $inner = preg_replace( '/<table/', '<table class="table table-striped"', $inner, 1 );
    $inner = preg_replace( '/<thead/', '<thead class="table-dark"',           $inner, 1 );

    return '<div class="table-responsive">' . $inner . '</div>';
}

If the table already has classes applied by the editor (via block settings), merge them instead of replacing:

<?php
// Merge Bootstrap class with any existing class attribute on <table>
$inner = preg_replace_callback(
    '/<table(\s[^>]*)?>/',
    function ( $m ) {
        $attrs = $m[1] ?? '';
        if ( preg_match( '/class="([^"]*)"/', $attrs, $cm ) ) {
            // Append Bootstrap classes to existing class value
            $attrs = str_replace( $cm[0], 'class="' . $cm[1] . ' table table-striped"', $attrs );
        } else {
            $attrs .= ' class="table table-striped"';
        }
        return '<table' . $attrs . '>';
    },
    $inner,
    1
);

NOTE: The render_block filter receives the rendered HTML string — not the block's stored JSON. This means the transformation runs on every front-end page load that contains a table. For high-traffic sites, this is fine because the regex operations are fast and the filter runs after any page caching reads the cached version. The filter does not affect the block editor preview — editors still see the default Gutenberg table styling while writing. If you need the Bootstrap styles in the editor as well, enqueue a Bootstrap CSS file via add_editor_style() separately. Also note that Gutenberg's Table block wraps content in <figure> — if a future WordPress update changes this structure, the regex match may fail silently and the <div class="table-responsive"> fallback ensures the table is still wrapped.

Sources:

  1. https://www.gsarigiannidis.gr/adding-a-div-wrapper-to-gutenberg-s-classic-block
  2. https://wordpress.org/support/topic/wrapping-gutenberg-block