📊 fix: Contain Markdown Table Overflow (#13543)
Some checks are pending
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Waiting to run
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Waiting to run
GitNexus Index / index (push) Waiting to run
GitNexus Index / post-index (push) Blocked by required conditions
Docker Dev Images Build / build (Dockerfile, librechat-dev, node) (push) Waiting to run
Docker Dev Images Build / build (Dockerfile.multi, librechat-dev-api, api-build) (push) Waiting to run
Sync Locize Translations & Create Translation PR / Sync Translation Keys with Locize (push) Waiting to run
Sync Locize Translations & Create Translation PR / Create Translation PR on Version Published (push) Blocked by required conditions
Sync Helm Chart Tags / Ignore non-main push (push) Waiting to run
Sync Helm Chart Tags / Sync chart tags (push) Waiting to run

* fix: Contain Markdown table overflow

* fix: Improve Markdown table scrollbar
This commit is contained in:
Danny Avila 2026-06-05 21:49:54 -04:00 committed by GitHub
parent 4b3fd63803
commit bede561f10
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 73 additions and 3 deletions

View file

@ -19,7 +19,7 @@ import { ArtifactProvider, CodeBlockProvider } from '~/Providers';
import MarkdownErrorBoundary from './MarkdownErrorBoundary';
import { langSubset, preprocessLaTeX } from '~/utils';
import { unicodeCitation } from '~/components/Web';
import { code, a, p, img } from './MarkdownComponents';
import { code, a, p, img, table } from './MarkdownComponents';
import store from '~/store';
type TContentProps = {
@ -88,6 +88,7 @@ const Markdown = memo(function Markdown({ content = '', isLatestMessage }: TCont
a,
p,
img,
table,
artifact: Artifact,
citation: Citation,
'highlighted-text': HighlightedText,

View file

@ -185,6 +185,19 @@ export const p: React.ElementType = memo(function MarkdownParagraph({ children }
});
p.displayName = 'MarkdownParagraph';
type TTableProps = {
children: React.ReactNode;
};
export const table: React.ElementType = memo(function MarkdownTable({ children }: TTableProps) {
return (
<div className="markdown-table-wrapper w-full max-w-full">
<table>{children}</table>
</div>
);
});
table.displayName = 'MarkdownTable';
type TImageProps = {
src?: string;
alt?: string;

View file

@ -4,7 +4,7 @@ import supersub from 'remark-supersub';
import ReactMarkdown from 'react-markdown';
import rehypeHighlight from 'rehype-highlight';
import type { PluggableList } from 'unified';
import { code, codeNoExecution, a, p } from './MarkdownComponents';
import { code, codeNoExecution, a, p, table } from './MarkdownComponents';
import { CodeBlockProvider } from '~/Providers';
import { langSubset } from '~/utils';
@ -72,6 +72,7 @@ class MarkdownErrorBoundary extends React.Component<
code: codeExecution ? code : codeNoExecution,
a,
p,
table,
} as {
[nodeType: string]: React.ElementType;
}

View file

@ -6,7 +6,7 @@ import supersub from 'remark-supersub';
import ReactMarkdown from 'react-markdown';
import rehypeHighlight from 'rehype-highlight';
import type { PluggableList } from 'unified';
import { code, codeNoExecution, a, p, img } from './MarkdownComponents';
import { code, codeNoExecution, a, p, img, table } from './MarkdownComponents';
import { CodeBlockProvider, ArtifactProvider } from '~/Providers';
import MarkdownErrorBoundary from './MarkdownErrorBoundary';
import { langSubset } from '~/utils';
@ -44,6 +44,7 @@ const MarkdownLite = memo(
a,
p,
img,
table,
} as {
[nodeType: string]: React.ElementType;
}

View file

@ -1,6 +1,7 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import Markdown from '../Markdown';
import MarkdownLite from '../MarkdownLite';
import { RecoilRoot } from 'recoil';
import { UI_RESOURCE_MARKER } from '~/components/MCPUIResource/plugin';
import {
@ -108,3 +109,35 @@ describe('Markdown with MCP UI markers (resource IDs)', () => {
expect(renderers[1]).toHaveAttribute('data-resource-uri', 'ui://weather/nyc');
});
});
describe('Markdown table rendering', () => {
const tableMarkdown = [
'| Alpha | Bravo | Charlie | Delta | Echo | Foxtrot | Golf | Hotel |',
'| --- | --- | --- | --- | --- | --- | --- | --- |',
'| one | two | three | four | five | six | seven | eight |',
].join('\n');
it('wraps GFM tables in a horizontally scrollable container', () => {
render(
<RecoilRoot>
<Markdown content={tableMarkdown} isLatestMessage={false} />
</RecoilRoot>,
);
expect(screen.getByRole('table').parentElement).toHaveClass(
'markdown-table-wrapper',
'w-full',
'max-w-full',
);
});
it('wraps lightweight Markdown tables in a horizontally scrollable container', () => {
render(<MarkdownLite content={tableMarkdown} />);
expect(screen.getByRole('table').parentElement).toHaveClass(
'markdown-table-wrapper',
'w-full',
'max-w-full',
);
});
});

View file

@ -1496,6 +1496,27 @@ button {
background-color: transparent;
}
.markdown-table-wrapper {
-webkit-overflow-scrolling: touch;
overflow-x: auto;
overscroll-behavior-x: contain;
padding-bottom: 0.25rem;
scrollbar-color: var(--border-medium) transparent;
scrollbar-width: thin;
}
.markdown-table-wrapper::-webkit-scrollbar {
height: 0.5rem;
}
.markdown-table-wrapper::-webkit-scrollbar-thumb {
background-color: var(--border-medium);
}
.markdown-table-wrapper::-webkit-scrollbar-thumb:hover {
background-color: var(--border-heavy);
}
/* Show scrollbar only on hover */
.scrollbar-hover {
scrollbar-width: thin;