From 35fc09b231a73d22adfc9ac9d5e437af6e592194 Mon Sep 17 00:00:00 2001 From: Aleksander Grygier Date: Fri, 18 Sep 2026 20:48:36 +0200 Subject: [PATCH] ui : wrap markdown tables in a scroll container Markdown tables render as a bare , which keeps its content-driven minimum width and can stretch the chat column past the window. The table-wrapper CSS already existed, but nothing produced the wrapper. Add a rehype plugin that wraps each table in div.table-wrapper, following the existing enhance-* plugins. Assisted-by: pi:deepseek-ai/DeepSeek-V4.1-Flash --- .../MarkdownContent/markdown-processor.ts | 2 ++ .../plugins/rehype/enhance-tables.ts | 34 +++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tools/ui/src/lib/components/app/content/MarkdownContent/plugins/rehype/enhance-tables.ts diff --git a/tools/ui/src/lib/components/app/content/MarkdownContent/markdown-processor.ts b/tools/ui/src/lib/components/app/content/MarkdownContent/markdown-processor.ts index e973a6a4b5..57ded3e99a 100644 --- a/tools/ui/src/lib/components/app/content/MarkdownContent/markdown-processor.ts +++ b/tools/ui/src/lib/components/app/content/MarkdownContent/markdown-processor.ts @@ -11,6 +11,7 @@ import { rehypeEnhanceCodeBlocks } from './plugins/rehype/enhance-code-blocks'; import { rehypeEnhanceLinks } from './plugins/rehype/enhance-links'; import { rehypeEnhanceMermaidBlocks } from './plugins/rehype/enhance-mermaid-blocks'; import { rehypeEnhanceSvgBlocks } from './plugins/rehype/enhance-svg-blocks'; +import { rehypeEnhanceTables } from './plugins/rehype/enhance-tables'; import { rehypeFileBadge } from './plugins/rehype/file-badge'; import { rehypeMermaidPre } from './plugins/rehype/mermaid-pre'; import { rehypeRtlSupport } from './plugins/rehype/rehype-rtl-support'; @@ -73,6 +74,7 @@ function buildPipeline({ languages: lowlightAll }) // Add syntax highlighting .use(rehypeRestoreTableHtml) // Restore limited HTML (e.g.
,
keeps its content-driven minimum width, which propagates up + * the layout and can stretch the chat column past the window. Wrapping in + * div.table-wrapper makes the wrapper the scroll container (styled in + * markdown-content.css), so wide tables scroll in place instead. + */ + +import type { Element, ElementContent, Root } from 'hast'; +import type { Plugin } from 'unified'; +import { visit } from 'unist-util-visit'; + +export const rehypeEnhanceTables: Plugin<[], Root> = () => { + return (tree: Root) => { + visit(tree, 'element', (node: Element, index, parent) => { + if (node.tagName !== 'table' || !parent || index === undefined) return; + + // already wrapped (e.g. nested tables in raw HTML input) + const parentClass = parent.type === 'element' ? parent.properties?.className : undefined; + + if (Array.isArray(parentClass) && parentClass.includes('table-wrapper')) return; + + const wrapper: Element = { + children: [node as ElementContent], + properties: { className: ['table-wrapper'] }, + tagName: 'div', + type: 'element' + }; + + parent.children[index] = wrapper; + }); + }; +};