Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions assets/scss/dark-theme/tables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
background-color: $color-gunpowder-gray;
border-bottom-color: $color-marlin-black;
}

&.restables-clone tbody td:first-child {
color: $color-white;
background-color: $color-gunpowder-gray;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
}

Expand Down
38 changes: 37 additions & 1 deletion assets/scss/tables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,44 @@
writing-mode: vertical-lr;
}
}

}

&.restables-clone {
display: none;
width: 100%;

tbody {
display: table;
width: 100%;
border-collapse: collapse;

+ tbody {
margin-top: 10px;
}

td {
box-shadow: none;
}

td:first-child {
width: 35%;
color: $color-black;
font-weight: 700;
background-color: $color-mist-gray;
}
}
}
}
}

.table-responsive--stacked {
table.restables-origin {
display: none;
}

table.restables-clone {
display: block;
}
}

Expand Down
3 changes: 2 additions & 1 deletion docs/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,10 @@ theme = ["GDCDocsTheme", "docsy"]
## Reference

| Page | Description |
|------|-------------|
| ---- | ----------- |
| [Markdown Reference](markdown-reference) | All Markdown formatting options with live rendered output. |
| [Shortcodes](shortcodes) | Every Hugo shortcode bundled with the theme. |
| [Table Examples](tables) | Live examples of all table variants, including responsive stacking for wide tables. |

## License

Expand Down
96 changes: 96 additions & 0 deletions docs/tables.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
---
title: "Table Examples"
linkTitle: "Table Examples"
weight: 30
type: docs
description: "Live examples of every table variant supported by the theme — basic Markdown tables, alignment, and responsive wide tables."
---

This page demonstrates how tables render in the GoodData Docs Theme. Every table on a docs page is automatically wrapped in a responsive container by `static/js/tables.js`. A table that does not fit its container is restacked into a two-column label/value layout by the [resTables](https://github.com/codefog/restables) plugin, with horizontal scrolling and a fade hint as the fallback for tables that cannot be restacked. All variants are styled for both the light and dark theme.

---

## Basic table

A standard Markdown pipe table. The header row gets a shaded background, and cells are separated by borders on all sides.

```markdown
| Name | Type | Required | Description |
|-------------|---------|----------|------------------------------------|
| `workspace` | string | Yes | Workspace identifier. |
| `title` | string | No | Human-readable dashboard title. |
| `tags` | array | No | Tags used for filtering and search.|
```

| Name | Type | Required | Description |
|-------------|---------|----------|------------------------------------|
| `workspace` | string | Yes | Workspace identifier. |
| `title` | string | No | Human-readable dashboard title. |
| `tags` | array | No | Tags used for filtering and search.|

---

## Column alignment

Control alignment with the position of `:` in the separator row.

```markdown
| Left-aligned | Centered | Right-aligned |
|:-------------|:--------:|--------------:|
| Metric | Active | 1,234.56 |
| Insight | Draft | 42.00 |
```

| Left-aligned | Centered | Right-aligned |
|:-------------|:--------:|--------------:|
| Metric | Active | 1,234.56 |
| Insight | Draft | 42.00 |

---

## Formatting inside cells

Cells support inline Markdown — code, emphasis, links, and even line breaks with `<br>`.

```markdown
| Element | Example |
|-----------------|--------------------------------------------------|
| Inline code | `SELECT * FROM metrics` |
| Bold / italic | **required**, *optional* |
| Link | [GoodData website](https://www.gooddata.com) |
| Multiple lines | First line<br>Second line |
```

| Element | Example |
|-----------------|--------------------------------------------------|
| Inline code | `SELECT * FROM metrics` |
| Bold / italic | **required**, *optional* |
| Link | [GoodData website](https://www.gooddata.com) |
| Multiple lines | First line<br>Second line |

---

## Responsive behavior

The theme makes every table responsive automatically — no shortcode or extra markup is needed. Instead of a fixed breakpoint, the theme checks whether each table actually fits its container (re-checked on every window resize):

- **Table fits:** it renders as a normal table, regardless of screen size.
- **Table is wider than its container:** the [resTables](https://github.com/codefog/restables) plugin swaps in a stacked two-column clone of the table, where each original row becomes a group of label/value pairs — no horizontal scrolling needed. Narrow the browser window until a table on this page stops fitting to see it restack.

Tables with merged cells (`rowspan`/`colspan`) or without a header row cannot be mapped to label/value pairs, so they keep their original layout. When such a table overflows, it falls back to scrolling horizontally with a fade overlay on the right edge as a visual hint that more content is available.

The wide table below is the easiest place to see the swap — as the window narrows, it is the first to stop fitting and restack:

| Endpoint | Method | Authentication | Rate limit | Request body | Response | Since version | Notes |
| -------- | ------ | -------------- | ---------- | ------------ | -------- | ------------- | ----- |
| `/api/v1/entities/workspaces` | GET | Bearer token | 100 req/min | — | JSON:API collection of workspaces | 1.0 | Supports `include`, `filter`, and pagination query parameters. |
| `/api/v1/entities/workspaces/{id}` | PUT | Bearer token | 60 req/min | JSON:API workspace document | Updated workspace entity | 1.0 | Requires the `MANAGE` permission on the workspace. |
| `/api/v1/actions/workspaces/{id}/execution` | POST | Bearer token | 30 req/min | Execution definition (AFM) | Execution result handle | 1.2 | Long-running executions return `202 Accepted` with a polling URL. |
| `/api/v1/layout/workspaces/{id}/logicalModel` | GET | Bearer token | 100 req/min | — | Declarative logical data model | 1.1 | Use `?includeParents=true` to include inherited datasets. |

---

## See also

- [Markdown Reference](markdown-reference) — all Markdown formatting options, including table syntax basics.
- [Shortcodes reference](shortcodes) — GoodData-specific components that extend Markdown.
1 change: 1 addition & 0 deletions layouts/partials/hooks/body-end.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{{/* (C) 2026 GoodData Corporation */}}
<script src="/js/menu.js"></script>
<script src="/js/dropdown.js"></script>
<script src="/js/restables.min.js"></script>
<script src="/js/tables.js"></script>
<script src="/js/share.js"></script>
<script src="/js/code-select.js"></script>
Expand Down
8 changes: 8 additions & 0 deletions static/js/restables.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

80 changes: 75 additions & 5 deletions static/js/tables.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,87 @@
// (C) 2026 GoodData Corporation

$(document).ready(function () {
const responsiveTable = function(wrapper) {
if (wrapper.width() === 0) {
return;
}

const hasClone = wrapper.find("table.restables-clone").length > 0;

wrapper.removeClass("table-responsive--stacked");
const table = wrapper.find("table").filter(":visible").first();
const overflows = table.length > 0 &&
(table[0].scrollWidth > table[0].clientWidth + 1 || table.width() > wrapper.width());

if (hasClone) {
wrapper.toggleClass("table-responsive--stacked", overflows);
}

const shown = wrapper.find("table").filter(":visible").first();
const shownOverflows = shown.length > 0 &&
(shown[0].scrollWidth > shown[0].clientWidth + 1 || shown.width() > wrapper.width());
wrapper.toggleClass("table-responsive__wide", shownOverflows);
};

const responsiveTables = function() {
$(".table-responsive").each(function() {
const wrapperWidth = $(this).width();
const tableWidth = $(this).find("table").width();
$(this).toggleClass("table-responsive__wide", tableWidth > wrapperWidth);
responsiveTable($(this));
});
}
};

$(".td-content table").wrap($("<div>").addClass("table-responsive")).wrap($("<div>").addClass("table-responsive__inner"));

if ($.fn.resTables) {
$(".td-content table").filter(function() {
const table = $(this);

if (table.hasClass("td-initial") ||
table.find("table").length > 0 || table.parents("table").length > 0 ||
table.find("[rowspan], [colspan]").length > 0) {
return false;
}

const headerRows = table.find("thead tr");
if (headerRows.length !== 1 || headerRows.find("td").length > 0) {
return false;
}
const headerCount = headerRows.find("th").length;
if (headerCount === 0) {
return false;
}

const bodyRows = table.find("tbody tr");
let regular = bodyRows.length > 0;
bodyRows.each(function() {
const row = $(this);
if (row.find("th").length > 0 || row.find("td").length !== headerCount) {
regular = false;
return false;
}
});
return regular;
}).resTables();
}

responsiveTables();
$(window).on("resize", responsiveTables);

if (window.ResizeObserver) {
const observer = new ResizeObserver(function(entries) {
entries.forEach(function(entry) {
const wrapper = $(entry.target);
const width = entry.contentRect.width;
if (wrapper.data("responsiveWidth") !== width) {
wrapper.data("responsiveWidth", width);
responsiveTable(wrapper);
}
});
});
$(".table-responsive").each(function() {
observer.observe(this);
});
} else {
$(window).on("resize", responsiveTables);
}

// Vertical column in tables - wrap around span
const verticalColumn = document.querySelector("tbody tr:first-child td[rowspan]:first-child");
Expand Down