Apply sticky table headers for markdown-rendered table views
What does this MR do and why?
Add sticky table headers for markdown tables in view mode
Wrap markdown tables with a bounded-height scroll container (max-height: 70vh) and apply position: sticky to thead cells. This keeps column headers visible when scrolling long tables.
Changelog: added
Screenshots or screen recordings
Tested in Chrome browser:
| Before | After |
|---|---|
Browsers
| Browser | Recording |
|---|---|
| Safari | |
| Firefox | |
| iPhone 14 Pro Max emulator |
How to set up and validate locally
The Ultimate Markdown Test Document
# The Ultimate Markdown Test DocumentThis document is designed to test frontend markdown rendering across a wide variety of syntax and edge cases.
1. Headings
H1 — The Quick Brown Fox
H2 — Jumps Over
H3 — The Lazy Dog
H4 — And Then Some
H5 — Going Deeper
H6 — As Deep As It Gets
2. Text Formatting
Regular paragraph text sits here, flowing naturally across the line. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Bold text and also bold appear in many places.
Italic text and also italic are slightly different but similar.
Bold and italic combined together.
Strikethrough text for deleted or deprecated content.
Inline code looks like this inline.
This is a line with a manual
line break (two trailing spaces).
This is a new paragraph after a blank line.
3. Blockquotes
This is a simple blockquote. It contains a single line of quoted content.
This is a longer blockquote. It spans multiple lines. Each line starts with a
>character.
Blockquote with heading
Blockquotes can also contain other markdown elements like bold, italic, and even lists:
- Item one
- Item two
- Item three
Pretty neat, right?
Nested blockquote level one
Nested blockquote level two
Nested blockquote level three
4. Lists
Unordered Lists
- Alpha
- Beta
- Gamma
- Gamma Sub-item 1
- Gamma Sub-item 2
- Deep nested item
- Another deep item
- Gamma Sub-item 3
- Delta
Ordered Lists
- First item
- Second item
- Third item
- Sub-item 3.1
- Sub-item 3.2
- Fourth item
- Fifth item
Mixed Lists
- Top-level ordered
- Unordered child
- Another unordered child
- Back to ordered
- Still ordered
- Back to top-level ordered
Task Lists
- Set up the project
- Write unit tests
- Deploy to staging
- Write documentation
- Deploy to production
-
Celebrate
🎉
5. Code Blocks
Inline Code
Use const instead of var whenever possible. Call the function like myFunc(arg1, arg2).
Fenced Code Block (JavaScript)
// A simple async fetch example
async function fetchData(url) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
} catch (err) {
console.error('Fetch failed:', err);
throw err;
}
}
const result = await fetchData('https://api.example.com/data');
console.log(result);
Fenced Code Block (Python)
from typing import Optional
import httpx
class APIClient:
def __init__(self, base_url: str, api_key: Optional[str] = None):
self.base_url = base_url
self.headers = {"Authorization": f"Bearer {api_key}"} if api_key else {}
async def get(self, endpoint: str) -> dict:
async with httpx.AsyncClient() as client:
response = await client.get(
f"{self.base_url}/{endpoint}",
headers=self.headers
)
response.raise_for_status()
return response.json()
# Usage
client = APIClient("https://api.example.com", api_key="secret-key")
data = await client.get("users/42")
print(data)
Fenced Code Block (SQL)
SELECT
u.id,
u.name,
u.email,
COUNT(o.id) AS total_orders,
SUM(o.amount) AS total_spent
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
WHERE u.created_at >= '2024-01-01'
AND u.is_active = TRUE
GROUP BY u.id, u.name, u.email
HAVING total_spent > 500
ORDER BY total_spent DESC
LIMIT 25;
Fenced Code Block (Bash)
#!/bin/bash
set -euo pipefail
APP_NAME="my-app"
VERSION=$(git describe --tags --always)
IMAGE="$APP_NAME:$VERSION"
echo "Building Docker image: $IMAGE"
docker build -t "$IMAGE" .
echo "Running tests..."
docker run --rm "$IMAGE" npm test
echo "Pushing to registry..."
docker tag "$IMAGE" "registry.example.com/$IMAGE"
docker push "registry.example.com/$IMAGE"
echo "Done! Version $VERSION deployed."
No-language Code Block
Plain preformatted text
with some indentation
and more indentation
No syntax highlighting here.
Tabs and spaces preserved.
6. Tables
Simple Table
| Name | Age | City |
|---|---|---|
| Alice | 30 | New York |
| Bob | 25 | Los Angeles |
| Charlie | 35 | Chicago |
| Diana | 28 | Houston |
Aligned Table
| Left-Aligned | Center-Aligned | Right-Aligned |
|---|---|---|
| Apple | Red | $1.20 |
| Banana | Yellow | $0.50 |
| Blueberry | Blue | $3.99 |
| Watermelon | Green/Red | $5.00 |
Wide Table
| Feature | Starter | Pro | Enterprise |
|---|---|---|---|
| Users | 5 | 25 | Unlimited |
| Storage | 10 GB | 100 GB | 10 TB |
| API Calls/month | 1,000 | 50,000 | Unlimited |
| Support | Chat | Dedicated | |
| Custom Domains | |||
| SSO | |||
| SLA | None | 99.9% | 99.99% |
| Price/month | Free | $49 | Contact Us |
7. Horizontal Rules
Three hyphens:
Three asterisks:
Three underscores:
8. Links
Auto-link: https://www.example.com
Auto-email: hello@example.com
9. Images
10. Footnotes
Here is a sentence with a footnote.1
Here is another sentence with a different footnote.2
11. Definition Lists (Extended Markdown)
- Markdown
- A lightweight markup language for creating formatted text.
- HTML
- HyperText Markup Language, the standard language for web pages.
- CSS
- Cascading Style Sheets, used for styling web documents.
12. Mathematical Notation (LaTeX-style)
Inline math: E = mc^2
Block math:
\int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}
\frac{\partial f}{\partial x} = \lim_{h \to 0} \frac{f(x+h) - f(x)}{h}
13. Miscellaneous
Escaping Characters
*Not italic* **Not bold** `Not code`
Long Unbroken String
averylongstringthatmightcauseoverflowissuesifnothandledproperlybythefrontendrenderer_averylongstringthatmightcauseoverflowissues
Emoji
Markdown renderers often support emoji shortcodes:
Or raw unicode emoji:
Special HTML Characters in Text
AT&T, 2 < 3, 5 > 4, "quoted text", 100% done.
14. Nested & Complex Structures
Blockquote containing a code block and a list
Here's a quoted section with embedded content:
const x = 42; console.log(x);And a list inside the quote:
- Step one
- Step two
- Step three
List containing blockquotes
- First point is straightforward.
- Second point includes a quote:
"We choose to go to the moon." — JFK
- Third point continues normally.
Table inside a section with other content
Below is a comparison of sorting algorithms:
| Algorithm | Best | Average | Worst | Space | Stable | Best | Average | Worst | Space | Stable |
|---|---|---|---|---|---|---|---|---|---|---|
| Bubble Sort | O(n) | O(n²) | O(n²) | O(1) | Yes | O(n) | O(n²) | O(n²) | O(1) | Yes |
| Merge Sort | O(n log n) | O(n log n) | O(n log n) | O(n) | Yes | O(n log n) | O(n log n) | O(n log n) | O(n) | Yes |
| Quick Sort | O(n log n) | O(n log n) | O(n²) | O(log n) | No | O(n log n) | O(n log n) | O(n²) | O(log n) | No |
| Heap Sort | O(n log n) | O(n log n) | O(n log n) | O(1) | No | O(n log n) | O(n log n) | O(n log n) | O(1) | No |
| Insertion Sort | O(n) | O(n²) | O(n²) | O(1) | Yes | O(n) | O(n²) | O(n²) | O(1) | Yes |
| Bubble Sort | O(n) | O(n²) | O(n²) | O(1) | Yes | O(n) | O(n²) | O(n²) | O(1) | Yes |
| Merge Sort | O(n log n) | O(n log n) | O(n log n) | O(n) | Yes | O(n log n) | O(n log n) | O(n log n) | O(n) | Yes |
| Quick Sort | O(n log n) | O(n log n) | O(n²) | O(log n) | No | O(n log n) | O(n log n) | O(n²) | O(log n) | No |
| Heap Sort | O(n log n) | O(n log n) | O(n log n) | O(1) | No | O(n log n) | O(n log n) | O(n log n) | O(1) | No |
| Insertion Sort | O(n) | O(n²) | O(n²) | O(1) | Yes | O(n) | O(n²) | O(n²) | O(1) | Yes |
| Bubble Sort | O(n) | O(n²) | O(n²) | O(1) | Yes | O(n) | O(n²) | O(n²) | O(1) | Yes |
| Merge Sort | O(n log n) | O(n log n) | O(n log n) | O(n) | Yes | O(n log n) | O(n log n) | O(n log n) | O(n) | Yes |
| Quick Sort | O(n log n) | O(n log n) | O(n²) | O(log n) | No | O(n log n) | O(n log n) | O(n²) | O(log n) | No |
| Heap Sort | O(n log n) | O(n log n) | O(n log n) | O(1) | No | O(n log n) | O(n log n) | O(n log n) | O(1) | No |
| Insertion Sort | O(n) | O(n²) | O(n²) | O(1) | Yes | O(n) | O(n²) | O(n²) | O(1) | Yes |
| Bubble Sort | O(n) | O(n²) | O(n²) | O(1) | Yes | O(n) | O(n²) | O(n²) | O(1) | Yes |
| Merge Sort | O(n log n) | O(n log n) | O(n log n) | O(n) | Yes | O(n log n) | O(n log n) | O(n log n) | O(n) | Yes |
| Quick Sort | O(n log n) | O(n log n) | O(n²) | O(log n) | No | O(n log n) | O(n log n) | O(n²) | O(log n) | No |
| Heap Sort | O(n log n) | O(n log n) | O(n log n) | O(1) | No | O(n log n) | O(n log n) | O(n log n) | O(1) | No |
| Insertion Sort | O(n) | O(n²) | O(n²) | O(1) | Yes | O(n) | O(n²) | O(n²) | O(1) | Yes |
| Bubble Sort | O(n) | O(n²) | O(n²) | O(1) | Yes | O(n) | O(n²) | O(n²) | O(1) | Yes |
| Merge Sort | O(n log n) | O(n log n) | O(n log n) | O(n) | Yes | O(n log n) | O(n log n) | O(n log n) | O(n) | Yes |
| Quick Sort | O(n log n) | O(n log n) | O(n²) | O(log n) | No | O(n log n) | O(n log n) | O(n²) | O(log n) | No |
| Heap Sort | O(n log n) | O(n log n) | O(n log n) | O(1) | No | O(n log n) | O(n log n) | O(n log n) | O(1) | No |
| Insertion Sort | O(n) | O(n²) | O(n²) | O(1) | Yes | O(n) | O(n²) | O(n²) | O(1) | Yes |
| Bubble Sort | O(n) | O(n²) | O(n²) | O(1) | Yes | O(n) | O(n²) | O(n²) | O(1) | Yes |
| Merge Sort | O(n log n) | O(n log n) | O(n log n) | O(n) | Yes | O(n log n) | O(n log n) | O(n log n) | O(n) | Yes |
| Quick Sort | O(n log n) | O(n log n) | O(n²) | O(log n) | No | O(n log n) | O(n log n) | O(n²) | O(log n) | No |
| Heap Sort | O(n log n) | O(n log n) | O(n log n) | O(1) | No | O(n log n) | O(n log n) | O(n log n) | O(1) | No |
| Insertion Sort | O(n) | O(n²) | O(n²) | O(1) | Yes | O(n) | O(n²) | O(n²) | O(1) | Yes |
| Bubble Sort | O(n) | O(n²) | O(n²) | O(1) | Yes | O(n) | O(n²) | O(n²) | O(1) | Yes |
| Merge Sort | O(n log n) | O(n log n) | O(n log n) | O(n) | Yes | O(n log n) | O(n log n) | O(n log n) | O(n) | Yes |
| Quick Sort | O(n log n) | O(n log n) | O(n²) | O(log n) | No | O(n log n) | O(n log n) | O(n²) | O(log n) | No |
| Heap Sort | O(n log n) | O(n log n) | O(n log n) | O(1) | No | O(n log n) | O(n log n) | O(n log n) | O(1) | No |
| Insertion Sort | O(n) | O(n²) | O(n²) | O(1) | Yes | O(n) | O(n²) | O(n²) | O(1) | Yes |
| Bubble Sort | O(n) | O(n²) | O(n²) | O(1) | Yes | O(n) | O(n²) | O(n²) | O(1) | Yes |
| Merge Sort | O(n log n) | O(n log n) | O(n log n) | O(n) | Yes | O(n log n) | O(n log n) | O(n log n) | O(n) | Yes |
| Quick Sort | O(n log n) | O(n log n) | O(n²) | O(log n) | No | O(n log n) | O(n log n) | O(n²) | O(log n) | No |
| Heap Sort | O(n log n) | O(n log n) | O(n log n) | O(1) | No | O(n log n) | O(n log n) | O(n log n) | O(1) | No |
| Insertion Sort | O(n) | O(n²) | O(n²) | O(1) | Yes | O(n) | O(n²) | O(n²) | O(1) | Yes |
Choose your algorithm based on the constraints of your specific use case.
15. Long Prose Section
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque vehicula, arcu non facilisis tincidunt, purus turpis consequat augue, sit amet tincidunt turpis leo ac nisl. Fusce euismod turpis at diam cursus, in tincidunt nisi facilisis. Sed non velit ut orci dictum cursus.
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra.
Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis.
A subsection within long prose
This subsection breaks up the long prose with a heading and continues with more content. The quick brown fox jumps over the lazy dog. The five boxing wizards jump quickly. How vexingly quick daft zebras jump! Pack my box with five dozen liquor jugs.
Curabitur pretium tincidunt lacus. Nulla gravida orci a odio. Nullam varius, turpis molestie dictum semper, diam lectus blandit dui, ut semper ipsum eros vel sapien. Duis commodo nisi lorem, a interdum lorem pharetra vel. Proin euismod augue in felis lacinia, vel pretium enim hendrerit.
query: assignee = currentUser()
fields: title, createdAt, milestone, assignee
title: Issues assigned to current user
End of test document. If you can see this, the markdown rendered correctly!
- Toggle on the Feature Flag
editor_sticky_table_headers - Go to a wiki page, e.g. http://gdk.test:3000/flightjs/Flight/-/wikis/home. If it does not exist yet, create the wiki
- Copy / paste the markdown above into it
- Scroll table at the bottom horizontally and vertically
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
Related to #585265