From 28926726cf7e93531d97b4210ec6e13d3bd0960a Mon Sep 17 00:00:00 2001 From: Hannah Issermann Date: Mon, 23 Mar 2026 09:37:20 +0100 Subject: [PATCH 01/22] Add draft tables --- scss/_tables.scss | 23 +++++++---- scss/_variables.scss | 11 ++--- site/data/components-details.ts | 21 ++++++++++ site/data/sidebar-components.yml | 1 - site/src/content/docs/components/table.mdx | 48 +++++++++++++++++++++- 5 files changed, 88 insertions(+), 16 deletions(-) diff --git a/scss/_tables.scss b/scss/_tables.scss index 2a62be0db0..7628655465 100644 --- a/scss/_tables.scss +++ b/scss/_tables.scss @@ -11,7 +11,7 @@ // End of reset --#{$prefix}table-color: #{$table-color}; --#{$prefix}table-bg: #{$table-bg}; - --#{$prefix}table-border-color: #{$table-border-color}; + --#{$prefix}table-border-color: #{$table-border-color}; // OK --#{$prefix}table-accent-bg: #{$table-accent-bg}; --#{$prefix}table-striped-color: #{$table-striped-color}; --#{$prefix}table-striped-bg: #{$table-striped-bg}; @@ -27,7 +27,14 @@ // OUDS mod //// Only rows have border //// Set line-height everywhere - tr { + + // stylelint-disable selector-no-qualifying-type + th[scope="col"], + th[scope="colgroup"] { + border-bottom: $table-header-border-width solid var(--#{$prefix}table-border-color); + } + + tr { border-bottom: $table-border-width solid var(--#{$prefix}table-border-color); } @@ -95,12 +102,12 @@ // Condensed table w/ half padding // -.table-sm { - // stylelint-disable-next-line selector-max-universal - > :not(caption) > * > * { - padding: $table-cell-padding-y-sm $table-cell-padding-x-sm calc($table-cell-padding-y-sm + 1px); // OUDS mod - } -} +//.table-sm { +// // stylelint-disable-next-line selector-max-universal +// > :not(caption) > * > * { +// padding: $table-cell-padding-y-sm $table-cell-padding-x-sm calc($table-cell-padding-y-sm + 1px); // OUDS mod +// } +//} // OUDS mod: no .table-bordered diff --git a/scss/_variables.scss b/scss/_variables.scss index a7fdcf9c6e..35f4d0aec8 100644 --- a/scss/_variables.scss +++ b/scss/_variables.scss @@ -788,10 +788,10 @@ $mark-bg: $ouds-color-action-highlighted-light !default; // // Customizes the `.table` component with basic values, each used across all table variations. // scss-docs-start table-variables -$table-cell-padding-y: .875rem !default; // OUDS mod -$table-cell-padding-x: $spacer * .5 !default; // OUDS mod -$table-cell-padding-y-sm: .5625rem !default; // OUDS mod -$table-cell-padding-x-sm: $table-cell-padding-x !default; // OUDS mod +$table-cell-padding-y: 1rem !default; // OUDS mod +$table-cell-padding-x: 1rem !default; // OUDS mod +//$table-cell-padding-y-sm: .5625rem !default; // OUDS mod +//$table-cell-padding-x-sm: $table-cell-padding-x !default; // OUDS mod $table-cell-icon-margin-top: -.75rem !default; // OUDS mod $table-cell-icon-margin-bottom: -.625rem !default; // OUDS mod @@ -820,7 +820,8 @@ $table-hover-bg: rgba(var(--#{$prefix}emphasis-color-rgb) $table-variant-hover-bg-factor: .2 !default; // OUDS mod $table-border-factor: .4 !default; // OUDS mod -$table-border-width: calc(var(--#{$prefix}border-width) * .5) !default; // OUDS mod +$table-header-border-width: 2px !default; // OUDS mod +$table-border-width: 1px !default; // OUDS mod $table-border-color: var(--#{$prefix}color-border-default) !default; // OUDS mod: instead of `var(--#{$prefix}border-color)` $table-striped-order: odd !default; diff --git a/site/data/components-details.ts b/site/data/components-details.ts index 3576d4a585..3ea5b39190 100644 --- a/site/data/components-details.ts +++ b/site/data/components-details.ts @@ -206,6 +206,27 @@ export const componentsDetails: ComponentCardData[] = [ ` }, + { + name: 'Table', + category: 'Content display', + snippet: ` + + + + + + + + + + + + + + + +
#FirstLast
1MarkOtto
` + }, { name: 'Tag', link: 'tags#tag', diff --git a/site/data/sidebar-components.yml b/site/data/sidebar-components.yml index b7e3c4a600..a8601244a1 100644 --- a/site/data/sidebar-components.yml +++ b/site/data/sidebar-components.yml @@ -67,7 +67,6 @@ draft: true - title: Switch - title: Table - draft: true - title: Tags - title: Text area - title: Text input diff --git a/site/src/content/docs/components/table.mdx b/site/src/content/docs/components/table.mdx index 3a2edd2b7f..8ab30ebcf5 100644 --- a/site/src/content/docs/components/table.mdx +++ b/site/src/content/docs/components/table.mdx @@ -1,5 +1,5 @@ --- -title: Tables +title: Table description: Documentation and examples for opt-in styling of tables (given their prevalent use in JavaScript plugins) with OUDS Web. aliases: - "/docs/content/tables/" @@ -7,4 +7,48 @@ aliases: toc: true --- - +import { getData } from '@libs/data' +import { getConfig } from '@libs/config' + +## Overview + +Due to the extensive use of `` elements in third-party widgets such as calendars and date pickers, OUDS Web’s tables are **opt-in**. This means that you must add the base class `.table` to any `
`, to benefit from OUDS Web's table styles which you can then extend with our optional modifier classes or custom styles. All table styles are not inherited in OUDS Web, meaning any nested tables can be styled independent of the parent. + +Using the most basic table markup, here’s how `.table`-based tables look in OUDS Web. + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OUDS Web basic table
#HeadingHeading
1CellCell
2CellCell
3CellCell
`} /> + +## Accessibility + +To make a table accessible, you should respect these main rules: + +- add a `scope="col"`, `scope="row"`, `scope="colgroup"`, or `scope="rowgroup"` attribute to the `` tags when needed to make the content of table readable by screen readers. +- add a `` on each table. If the table doesn’t have a caption or if the caption is not enough informative to describe the table, add an `aria-label` attribute to describe the table content. The `aria-label` should match the following pattern: `aria-label="Description of table data - Description of table metadata (e.g.: table with one level of column header)"`. The metadata is mandatory for complex tables. + +See [more information about the tables structures](https://a11y-guidelines.orange.com/en/web/develop/textual-content/#structuring-data-tables). From 7d5aa5011038ecde0b18984f95584a5bf0b7ae7b Mon Sep 17 00:00:00 2001 From: Hannah Issermann Date: Mon, 23 Mar 2026 17:53:53 +0100 Subject: [PATCH 02/22] Tables with table-responsive doc + row selection doc and styles --- scss/_tables.scss | 24 +- scss/_variables.scss | 10 +- site/data/components-details.ts | 6 +- site/data/sidebar-components.yml | 1 + site/src/assets/partials/snippets.js | 9 + site/src/content/docs/components/table.mdx | 344 ++++++++++++++++++++- 6 files changed, 379 insertions(+), 15 deletions(-) diff --git a/scss/_tables.scss b/scss/_tables.scss index 7628655465..a7fe20251c 100644 --- a/scss/_tables.scss +++ b/scss/_tables.scss @@ -1,6 +1,11 @@ // // Basic OUDS Web table // +%row-selection { + width: calc($ouds-checkbox-size-min-width + $core-ouds-dimension-50); + padding: 0; + vertical-align: middle; +} .table { // Reset needed for nesting tables @@ -71,9 +76,14 @@ // OUDS mod // When using checkboxes in the first column, force width to ensure correct spacing on this column - &.has-checkbox tr > :first-child { - width: $spacer * 2; - max-width: $spacer * 2; + &.has-row-selection tr > :first-child { + @extend %row-selection; + } + + @if $enable-bootstrap-compatibility { + &.has-checkbox tr > :first-child { + @extend %row-selection; + } } // Use negative margins on icons in tables to preserve row height @@ -118,13 +128,19 @@ // Default zebra-stripe styles (alternating gray and transparent backgrounds) // For rows -.table-striped { +.table-zebra { > tbody > tr:nth-of-type(#{$table-striped-order}) > * { --#{$prefix}table-color-type: var(--#{$prefix}table-striped-color); --#{$prefix}table-bg-type: var(--#{$prefix}table-striped-bg); } } +@if $enable-bootstrap-compatibility { + .table-striped { + @extend .table-zebra; + } +} + // For columns .table-striped-columns { > :not(caption) > tr > :nth-child(#{$table-striped-columns-order}) { diff --git a/scss/_variables.scss b/scss/_variables.scss index 35f4d0aec8..759637e071 100644 --- a/scss/_variables.scss +++ b/scss/_variables.scss @@ -788,8 +788,8 @@ $mark-bg: $ouds-color-action-highlighted-light !default; // // Customizes the `.table` component with basic values, each used across all table variations. // scss-docs-start table-variables -$table-cell-padding-y: 1rem !default; // OUDS mod -$table-cell-padding-x: 1rem !default; // OUDS mod +$table-cell-padding-y: $core-ouds-dimension-200 !default; // OUDS mod +$table-cell-padding-x: $core-ouds-dimension-200 !default; // OUDS mod //$table-cell-padding-y-sm: .5625rem !default; // OUDS mod //$table-cell-padding-x-sm: $table-cell-padding-x !default; // OUDS mod @@ -806,7 +806,7 @@ $table-th-font-weight: null !default; $table-striped-color: $table-color !default; $table-striped-bg-factor: .035 !default; // OUDS mod: equivalent to `$gray-200` -$table-striped-bg: rgba(var(--#{$prefix}black-rgb), var(--#{$prefix}table-striped-bg-factor)) !default; // OUDS mod: instead of `rgba(var(--#{$prefix}emphasis-color-rgb), $table-striped-bg-factor)` +$table-striped-bg: var(--#{$prefix}color-bg-secondary) !default; // OUDS mod: instead of `rgba(var(--#{$prefix}emphasis-color-rgb), $table-striped-bg-factor)` $table-variant-striped-bg-factor: .08 !default; // OUDS mod $table-active-color: $table-color !default; @@ -824,8 +824,8 @@ $table-header-border-width: 2px !default; // OUDS mod $table-border-width: 1px !default; // OUDS mod $table-border-color: var(--#{$prefix}color-border-default) !default; // OUDS mod: instead of `var(--#{$prefix}border-color)` -$table-striped-order: odd !default; -$table-striped-columns-order: even !default; +$table-striped-order: even !default; // OUDS mod +$table-striped-columns-order: odd !default; // OUDS mod $table-group-separator-color: currentcolor !default; diff --git a/site/data/components-details.ts b/site/data/components-details.ts index 3ea5b39190..5f6c6db72e 100644 --- a/site/data/components-details.ts +++ b/site/data/components-details.ts @@ -215,14 +215,14 @@ export const componentsDetails: ComponentCardData[] = [ # First - Last + Second 1 - Mark - Otto + Cell + Cell ` diff --git a/site/data/sidebar-components.yml b/site/data/sidebar-components.yml index a8601244a1..b7e3c4a600 100644 --- a/site/data/sidebar-components.yml +++ b/site/data/sidebar-components.yml @@ -67,6 +67,7 @@ draft: true - title: Switch - title: Table + draft: true - title: Tags - title: Text area - title: Text input diff --git a/site/src/assets/partials/snippets.js b/site/src/assets/partials/snippets.js index aa91de9724..22c9fdb56f 100644 --- a/site/src/assets/partials/snippets.js +++ b/site/src/assets/partials/snippets.js @@ -192,4 +192,13 @@ export default () => { }, false) }) // storybook-end offcanvas + + // ------------------------------- + // Table + // ------------------------------- + // Indeterminate checkbox in table example in docs and StackBlitz + // storybook-start table + const tableSelectAll = document.querySelector('.has-row-selection #tableSelectAll') + tableSelectAll.indeterminate = true + // storybook-end table } diff --git a/site/src/content/docs/components/table.mdx b/site/src/content/docs/components/table.mdx index 8ab30ebcf5..b49e55e224 100644 --- a/site/src/content/docs/components/table.mdx +++ b/site/src/content/docs/components/table.mdx @@ -8,7 +8,12 @@ toc: true --- import { getData } from '@libs/data' -import { getConfig } from '@libs/config' + + + The table component is not yet designed, and this component is only a draft for the moment. It will be updated in the future with the final design and will certainly need adjustments regarding the DOM. Use it as a temporary component to speed up your development. + + Please refer to the [Tables in the Boosted documentation](https://boosted.orange.com/docs/content/tables/) to have a full view of the header component and its variations. You’ll only need to adapt the utilities inside the DOM. + ## Overview @@ -48,7 +53,340 @@ Using the most basic table markup, here’s how `.table`-based tables look in OU To make a table accessible, you should respect these main rules: -- add a `scope="col"`, `scope="row"`, `scope="colgroup"`, or `scope="rowgroup"` attribute to the `` tags when needed to make the content of table readable by screen readers. -- add a `` on each table. If the table doesn’t have a caption or if the caption is not enough informative to describe the table, add an `aria-label` attribute to describe the table content. The `aria-label` should match the following pattern: `aria-label="Description of table data - Description of table metadata (e.g.: table with one level of column header)"`. The metadata is mandatory for complex tables. +- Add a `scope="col"`, `scope="row"`, `scope="colgroup"`, or `scope="rowgroup"` attribute to the `` tags when needed to make the content of table readable by screen readers. +- Add a `` on each table. If the table doesn’t have a caption or if the caption is not enough informative to describe the table, add an `aria-label` attribute to describe the table content. The `aria-label` should match the following pattern: `aria-label="Description of table data - Description of table metadata (e.g.: table with one level of column header)"`. The metadata is mandatory for complex tables. See [more information about the tables structures](https://a11y-guidelines.orange.com/en/web/develop/textual-content/#structuring-data-tables). + +## Variants + +### Zebra + +To create a striped table, add the `.table-zebra` modifier class to the base `.table` class. This will add a background color to even rows (not including the header) to improve readability. + + + OUDS Web zebra table + + + # + Heading + Heading + + + + + 1 + Cell + Cell + + + 2 + Cell + Cell + + + 3 + Cell + Cell + + + `} /> + +## Responsive tables + +Responsive tables allow tables to be scrolled horizontally with ease. Make any table responsive across all viewports by wrapping a `.table` with `.table-responsive`. Or, pick a maximum breakpoint with which to have a responsive table up to by using `.table-responsive{-sm|-md|-lg|-xl|-xxl}`. + + + ##### Vertical clipping/truncation + + Responsive tables make use of `overflow-y: hidden`, which clips off any content that goes beyond the bottom or top edges of the table. In particular, this can clip off dropdown menus and other third-party widgets. + + +### Always responsive + +Across every breakpoint, use `.table-responsive` for horizontally scrolling tables. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Boosted responsive table
#HeadingHeadingHeadingHeadingHeadingHeadingHeadingHeadingHeading
1CellCellCellCellCellCellCellCellCell
2CellCellCellCellCellCellCellCellCell
3CellCellCellCellCellCellCellCellCell
+ `} /> + + + + ... +
+ `} /> + +### Breakpoint specific + +Use `.table-responsive{-xs|-sm|-md|-lg|-xl|-2xl|3xl}` as needed to create responsive tables up to a particular breakpoint. From that breakpoint and up, the table will behave normally and not scroll horizontally. + +**These tables may appear broken until their responsive styles apply at specific viewport widths.** + +
+Example of tables responsive up to particular breakpoint +{getData('breakpoints').map((breakpoint) => { +return ( +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Boosted responsive table for {breakpoint.abbr} breakpoint and under
#HeadingHeadingHeadingHeadingHeadingHeadingHeadingHeading
1CellCellCellCellCellCellCellCell
2CellCellCellCellCellCellCellCell
3CellCellCellCellCellCellCellCell
+
+
+) +})} + + `
+ + ... +
+
`)} /> + +
+ +## Rich content tables + +### Row selection + +When using checkboxes, radio buttons or switches in tables, you should add the `.has-row-selection` modifier class to the base `.table` class. This will add the necessary padding to the first column to accommodate these control items. The control items should be placed in the first column, and the type of control items should obviously not be mixed. + +For the row selection purpose, you should use [standalone checkboxes]([[docsref:/components/checkbox#standalone]]), [standalone radio buttons]([[docsref:/components/radio-utton#standalone]]), or [standalone switches]([[docsref:/components/switch#standalone]]) with `.visually-hidden` labels describing their use. + +If the control items are checkboxes, the first cell of the header sould contain a checkbox to select or deselect all rows. If some rows are selected, the header checkbox should be in an [indeterminate state]([[docsref:/components/checkbox#indeterminate]]) to indicate this. + + + OUDS Web table with row selection + + + + + + Heading + Heading + + + + + + + + Cell + Cell + + + + + + Cell + Cell + + + + + + Cell + Cell + + + `} /> + + + OUDS Web table with radio buttons + + + Heading + Heading + Heading + + + + + + + + Cell + Cell + + + + + + Cell + Cell + + + + + + Cell + Cell + + + `} /> + + + OUDS Web table with switches + + + Heading + Heading + Heading + + + + + + + + Cell + Cell + + + + + + Cell + Cell + + + + + + Cell + Cell + + + `} /> From 64e72663714a5387a560da3efd236e18a4cc9343 Mon Sep 17 00:00:00 2001 From: Hannah Issermann Date: Tue, 24 Mar 2026 12:18:14 +0100 Subject: [PATCH 03/22] Fix link --- site/src/content/docs/components/table.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/src/content/docs/components/table.mdx b/site/src/content/docs/components/table.mdx index b49e55e224..4cb0a30d58 100644 --- a/site/src/content/docs/components/table.mdx +++ b/site/src/content/docs/components/table.mdx @@ -253,7 +253,7 @@ return ( When using checkboxes, radio buttons or switches in tables, you should add the `.has-row-selection` modifier class to the base `.table` class. This will add the necessary padding to the first column to accommodate these control items. The control items should be placed in the first column, and the type of control items should obviously not be mixed. -For the row selection purpose, you should use [standalone checkboxes]([[docsref:/components/checkbox#standalone]]), [standalone radio buttons]([[docsref:/components/radio-utton#standalone]]), or [standalone switches]([[docsref:/components/switch#standalone]]) with `.visually-hidden` labels describing their use. +For the row selection purpose, you should use [standalone checkboxes]([[docsref:/components/checkbox#standalone]]), [standalone radio buttons]([[docsref:/components/radio-button#standalone]]), or [standalone switches]([[docsref:/components/switch#standalone]]) with `.visually-hidden` labels describing their use. If the control items are checkboxes, the first cell of the header sould contain a checkbox to select or deselect all rows. If some rows are selected, the header checkbox should be in an [indeterminate state]([[docsref:/components/checkbox#indeterminate]]) to indicate this. From 0ca2a202a9926b4e00889fb23c1c7d01d5503683 Mon Sep 17 00:00:00 2001 From: Hannah Issermann Date: Fri, 27 Mar 2026 09:20:37 +0100 Subject: [PATCH 04/22] Row selection --- scss/_tables.scss | 22 ++++++++++++++++------ scss/_variables.scss | 4 ++-- site/src/assets/partials/snippets.js | 6 ++++++ site/src/content/docs/components/table.mdx | 16 +++++++++++++--- 4 files changed, 37 insertions(+), 11 deletions(-) diff --git a/scss/_tables.scss b/scss/_tables.scss index a7fe20251c..603ecc2096 100644 --- a/scss/_tables.scss +++ b/scss/_tables.scss @@ -7,6 +7,11 @@ vertical-align: middle; } +%row-active { + --#{$prefix}table-color-state: var(--#{$prefix}table-active-color); + --#{$prefix}table-bg-state: var(--#{$prefix}table-active-bg); +} + .table { // Reset needed for nesting tables --#{$prefix}table-color-type: initial; @@ -80,6 +85,13 @@ @extend %row-selection; } + // Automatically highlight rows with checked checkboxes + &.has-row-selection tbody tr:has(.control-item-indicator[type="checkbox"]:checked), + &.has-row-selection tbody tr:has(.control-item-indicator[type="radio"]:checked) { + @extend %row-active; + @extend [data-bs-theme=root-inverted]; + } + @if $enable-bootstrap-compatibility { &.has-checkbox tr > :first-child { @extend %row-selection; @@ -154,8 +166,7 @@ // The `.table-active` class can be added to highlight rows or cells .table-active { - --#{$prefix}table-color-state: var(--#{$prefix}table-active-color); - --#{$prefix}table-bg-state: var(--#{$prefix}table-active-bg); + @extend %row-active; } // Hover effect @@ -172,10 +183,9 @@ // Table variants set the table cell backgrounds, border colors // and the colors of the striped, hovered & active tables -@each $color, $value in $table-variants { - @include table-variant($color, $value); -} - +//@each $color, $value in $table-variants { +// @include table-variant($color, $value); +//} // Responsive tables // diff --git a/scss/_variables.scss b/scss/_variables.scss index 759637e071..c1d1e2059a 100644 --- a/scss/_variables.scss +++ b/scss/_variables.scss @@ -809,9 +809,9 @@ $table-striped-bg-factor: .035 !default; // OUDS mod: equivalent t $table-striped-bg: var(--#{$prefix}color-bg-secondary) !default; // OUDS mod: instead of `rgba(var(--#{$prefix}emphasis-color-rgb), $table-striped-bg-factor)` $table-variant-striped-bg-factor: .08 !default; // OUDS mod -$table-active-color: $table-color !default; +$table-active-color: var(--#{$prefix}color-content-inverse) !default; $table-active-bg-factor: .135 !default; // OUDS mod -$table-active-bg: rgba(var(--#{$prefix}emphasis-color-rgb), var(--#{$prefix}table-active-bg-factor)) !default; // OUDS mod: instead of `rgba(var(--#{$prefix}emphasis-color-rgb), $table-active-bg-factor)` +$table-active-bg: var(--#{$prefix}color-bg-inverse-low) !default; // OUDS mod: instead of `rgba(var(--#{$prefix}emphasis-color-rgb), $table-active-bg-factor)` $table-variant-active-bg-factor: .4 !default; // OUDS mod $table-hover-color: $table-color !default; diff --git a/site/src/assets/partials/snippets.js b/site/src/assets/partials/snippets.js index ec23074fc4..716214ea3a 100644 --- a/site/src/assets/partials/snippets.js +++ b/site/src/assets/partials/snippets.js @@ -256,5 +256,11 @@ export default () => { // storybook-start table const tableSelectAll = document.querySelector('.has-row-selection #tableSelectAll') tableSelectAll.indeterminate = true + + document.querySelectorAll('.has-row-selection tr:has(.control-item-indicator[type="checkbox"]:checked), ' + + '.has-row-selection tr:has(.control-item-indicator[type="radio"]:checked)').forEach(row => { + row.setAttribute('aria-selected', 'true') + row.setAttribute('data-bs-theme', 'root-inverted') + }) // storybook-end table } diff --git a/site/src/content/docs/components/table.mdx b/site/src/content/docs/components/table.mdx index 4cb0a30d58..74b970a8f7 100644 --- a/site/src/content/docs/components/table.mdx +++ b/site/src/content/docs/components/table.mdx @@ -89,6 +89,11 @@ To create a striped table, add the `.table-zebra` modifier class to the base `.t Cell Cell + + 4 + Cell + Cell + `} /> @@ -178,7 +183,7 @@ Use `.table-responsive{-xs|-sm|-md|-lg|-xl|-2xl|3xl}` as needed to create respon **These tables may appear broken until their responsive styles apply at specific viewport widths.**
-Example of tables responsive up to particular breakpoint +Examples of responsive tables up to particular breakpoint {getData('breakpoints').map((breakpoint) => { return (
@@ -239,7 +244,7 @@ return ( ) })} - `
+ `
...
@@ -255,7 +260,12 @@ When using checkboxes, radio buttons or switches in tables, you should add the ` For the row selection purpose, you should use [standalone checkboxes]([[docsref:/components/checkbox#standalone]]), [standalone radio buttons]([[docsref:/components/radio-button#standalone]]), or [standalone switches]([[docsref:/components/switch#standalone]]) with `.visually-hidden` labels describing their use. -If the control items are checkboxes, the first cell of the header sould contain a checkbox to select or deselect all rows. If some rows are selected, the header checkbox should be in an [indeterminate state]([[docsref:/components/checkbox#indeterminate]]) to indicate this. +If the control items are checkboxes, the first cell of the header should contain a checkbox to select or deselect all rows. If some rows are selected, the header checkbox should be in an [indeterminate state]([[docsref:/components/checkbox#indeterminate]]) to indicate this. + +If the control items are checkboxes or radio buttons, selecting a row will automtically apply some styles to visually indicate that the row is selected. If you want to manually apply the same styles to rows or even cells, you can use the class `.table-active` on the `` or `` elements. + + +to visually indicate that a row is selected (except the header row), add the `.table-active` class to the `` element. This applies a background color to highlight the selected row, ensuring users can easily identify which rows are currently selected. OUDS Web table with row selection From bf80387d56a9f5554cfa61da9d5ec1bb6fa14a8b Mon Sep 17 00:00:00 2001 From: Hannah Issermann Date: Fri, 27 Mar 2026 17:52:37 +0100 Subject: [PATCH 05/22] Row selection and live example --- site/data/sidebar-components.yml | 4 +- site/src/assets/partials/snippets.js | 102 ++++++++++++++------- site/src/content/docs/components/table.mdx | 16 ++-- 3 files changed, 78 insertions(+), 44 deletions(-) diff --git a/site/data/sidebar-components.yml b/site/data/sidebar-components.yml index ecb49fdabc..8b1b7653cf 100644 --- a/site/data/sidebar-components.yml +++ b/site/data/sidebar-components.yml @@ -17,6 +17,8 @@ - title: Select input - title: Skeleton - title: Switch + - title: Table + draft: true - title: Tags - title: Text area - title: Text input @@ -73,8 +75,6 @@ coming_soon: true - title: Sticker coming_soon: true - - title: Table - coming_soon: true - title: Title bar coming_soon: true - title: Toast diff --git a/site/src/assets/partials/snippets.js b/site/src/assets/partials/snippets.js index 716214ea3a..efccd4c1ad 100644 --- a/site/src/assets/partials/snippets.js +++ b/site/src/assets/partials/snippets.js @@ -198,37 +198,36 @@ export default () => { // ------------------------------- // First example // js-docs-start skeleton-first-example - const skeletonToReplace = document.querySelector('.bd-skeleton-replace') - const originalContent = skeletonToReplace.innerHTML - function replaceSkeleton() { setTimeout(() => { skeletonToReplace.innerHTML = `
- -
-

Placeholder title

-

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nec risus et risus consectetur dignissim volutpat ut lorem. Aenean posuere elementum massa, ac elementum magna auctor quis. Aliquam erat volutpat. Ut quam turpis, interdum non ex at, imperdiet ornare mi.

+ +
+

Placeholder title

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nec risus et risus consectetur dignissim volutpat ut lorem. Aenean posuere elementum massa, ac elementum magna auctor quis. Aliquam erat volutpat. Ut quam turpis, interdum non ex at, imperdiet ornare mi.

+
-
- - ` + + ` }, 8000) } - document.addEventListener('DOMContentLoaded', () => { - replaceSkeleton() - }) + const skeletonToReplace = document.querySelector('.bd-skeleton-replace') + if (skeletonToReplace) { + const originalContent = skeletonToReplace.innerHTML + document.addEventListener('DOMContentLoaded', () => { + replaceSkeleton() + }) - window.relaunchAnim = () => { - skeletonToReplace.innerHTML = originalContent - replaceSkeleton() + window.relaunchAnim = () => { + skeletonToReplace.innerHTML = originalContent + replaceSkeleton() + } } // js-docs-end skeleton-first-example // Second example // js-docs-start skeleton-second-example - const skeletonToReplace2 = document.querySelector('.bd-skeleton-replace2') - function removeSkeletons() { setTimeout(() => { skeletonToReplace2.firstElementChild.removeAttribute('inert') @@ -237,15 +236,18 @@ export default () => { }, 8000) } - document.addEventListener('DOMContentLoaded', () => { - removeSkeletons() - }) + const skeletonToReplace2 = document.querySelector('.bd-skeleton-replace2') + if (skeletonToReplace2) { + document.addEventListener('DOMContentLoaded', () => { + removeSkeletons() + }) - window.relaunchAnim2 = () => { - skeletonToReplace2.firstElementChild.setAttribute('inert', '') - skeletonToReplace2.firstElementChild.setAttribute('aria-busy', 'true') - skeletonToReplace2.lastElementChild.textContent = 'Loading form ...' - removeSkeletons() + window.relaunchAnim2 = () => { + skeletonToReplace2.firstElementChild.setAttribute('inert', '') + skeletonToReplace2.firstElementChild.setAttribute('aria-busy', 'true') + skeletonToReplace2.lastElementChild.textContent = 'Loading form ...' + removeSkeletons() + } } // js-docs-end skeleton-second-example @@ -254,13 +256,45 @@ export default () => { // ------------------------------- // Indeterminate checkbox in table example in docs and StackBlitz // storybook-start table - const tableSelectAll = document.querySelector('.has-row-selection #tableSelectAll') - tableSelectAll.indeterminate = true - - document.querySelectorAll('.has-row-selection tr:has(.control-item-indicator[type="checkbox"]:checked), ' + - '.has-row-selection tr:has(.control-item-indicator[type="radio"]:checked)').forEach(row => { - row.setAttribute('aria-selected', 'true') - row.setAttribute('data-bs-theme', 'root-inverted') - }) + // js-docs-start live-row-selection + // Manage checkboxes states (e.g., select/deselect all rows, update header checkbox state) + const tableSelectAll = document.querySelector('.has-row-selection#tableWithCheckboxes #tableSelectAll') + const allCheckboxes = document.querySelectorAll('.has-row-selection#tableWithCheckboxes tbody input[type="checkbox"]') + + function updateSelectAllState() { + const checkedCheckboxes = document.querySelectorAll('.has-row-selection#tableWithCheckboxes tbody input[type="checkbox"]:checked') + + if (checkedCheckboxes.length === 0) { + // None are checked + tableSelectAll.checked = false + tableSelectAll.indeterminate = false + } else if (checkedCheckboxes.length === allCheckboxes.length) { + // All are checked + tableSelectAll.checked = true + tableSelectAll.indeterminate = false + } else { + // Some are checked + tableSelectAll.checked = false + tableSelectAll.indeterminate = true + } + } + + if (tableSelectAll) { + tableSelectAll.addEventListener('change', event => { + allCheckboxes.forEach(checkbox => { + checkbox.checked = event.target.checked + }) + updateSelectAllState() + }) + + // Add change listener to all row checkboxes + allCheckboxes.forEach(checkbox => { + checkbox.addEventListener('change', updateSelectAllState) + }) + + // Initialize the state on load + updateSelectAllState() + } + // js-docs-end live-row-selection // storybook-end table } diff --git a/site/src/content/docs/components/table.mdx b/site/src/content/docs/components/table.mdx index 74b970a8f7..25d1f4a3d8 100644 --- a/site/src/content/docs/components/table.mdx +++ b/site/src/content/docs/components/table.mdx @@ -262,12 +262,9 @@ For the row selection purpose, you should use [standalone checkboxes]([[docsref: If the control items are checkboxes, the first cell of the header should contain a checkbox to select or deselect all rows. If some rows are selected, the header checkbox should be in an [indeterminate state]([[docsref:/components/checkbox#indeterminate]]) to indicate this. -If the control items are checkboxes or radio buttons, selecting a row will automtically apply some styles to visually indicate that the row is selected. If you want to manually apply the same styles to rows or even cells, you can use the class `.table-active` on the `` or `` elements. +If the control items are checkboxes or radio buttons, selecting a row will automtically apply some styles to visually indicate that the row is selected. If you want to manually apply the same styles to rows or even cells, you can use the class `.table-active` on `` or `` elements. - -to visually indicate that a row is selected (except the header row), add the `.table-active` class to the `` element. This applies a background color to highlight the selected row, ensuring users can easily identify which rows are currently selected. - - + OUDS Web table with row selection @@ -315,11 +312,14 @@ to visually indicate that a row is selected (except the header row), add the `.t `} /> - +To manage checkboxes states (e.g., select/deselect all rows, update header checkbox state), here is an example of JavaScript code: + + + OUDS Web table with radio buttons - Heading + Select Heading Heading @@ -362,7 +362,7 @@ to visually indicate that a row is selected (except the header row), add the `.t OUDS Web table with switches - Heading + Select Heading Heading From 9c83e42cb9ab66d304175f6bc59f39a37b951f67 Mon Sep 17 00:00:00 2001 From: Hannah Issermann Date: Fri, 27 Mar 2026 17:53:12 +0100 Subject: [PATCH 06/22] Row selection and live example --- scss/{_tables.scss => _table.scss} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename scss/{_tables.scss => _table.scss} (99%) diff --git a/scss/_tables.scss b/scss/_table.scss similarity index 99% rename from scss/_tables.scss rename to scss/_table.scss index 603ecc2096..4b9de24265 100644 --- a/scss/_tables.scss +++ b/scss/_table.scss @@ -86,7 +86,7 @@ } // Automatically highlight rows with checked checkboxes - &.has-row-selection tbody tr:has(.control-item-indicator[type="checkbox"]:checked), + &.has-row-selection tbody tr:has(.control-item-indicator[type="checkbox"]:not([role="switch"]):checked), &.has-row-selection tbody tr:has(.control-item-indicator[type="radio"]:checked) { @extend %row-active; @extend [data-bs-theme=root-inverted]; From c65aa0df655eb2b27d7ae9b692b15ef8f66fbdaa Mon Sep 17 00:00:00 2001 From: Hannah Issermann Date: Fri, 27 Mar 2026 17:59:26 +0100 Subject: [PATCH 07/22] Move tables to table --- packages/orange-compact/scss/ouds-web.scss | 2 +- packages/orange/scss/ouds-web.scss | 2 +- packages/sosh/scss/ouds-web.scss | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/orange-compact/scss/ouds-web.scss b/packages/orange-compact/scss/ouds-web.scss index 142340eefc..ac4b885dff 100644 --- a/packages/orange-compact/scss/ouds-web.scss +++ b/packages/orange-compact/scss/ouds-web.scss @@ -19,7 +19,7 @@ @import "@ouds/web-common/scss/images"; @import "@ouds/web-common/scss/containers"; @import "@ouds/web-common/scss/grid"; -@import "@ouds/web-common/scss/tables"; +@import "@ouds/web-common/scss/table"; @import "@ouds/web-common/scss/forms"; @import "@ouds/web-common/scss/links"; // OUDS mod @import "@ouds/web-common/scss/bullet-list"; // OUDS mod diff --git a/packages/orange/scss/ouds-web.scss b/packages/orange/scss/ouds-web.scss index e7c1520c36..92cbe10b3e 100644 --- a/packages/orange/scss/ouds-web.scss +++ b/packages/orange/scss/ouds-web.scss @@ -19,7 +19,7 @@ @import "@ouds/web-common/scss/images"; @import "@ouds/web-common/scss/containers"; @import "@ouds/web-common/scss/grid"; -@import "@ouds/web-common/scss/tables"; +@import "@ouds/web-common/scss/table"; @import "@ouds/web-common/scss/forms"; @import "@ouds/web-common/scss/links"; // OUDS mod @import "@ouds/web-common/scss/bullet-list"; // OUDS mod diff --git a/packages/sosh/scss/ouds-web.scss b/packages/sosh/scss/ouds-web.scss index 4d2b322fc0..c59f318311 100644 --- a/packages/sosh/scss/ouds-web.scss +++ b/packages/sosh/scss/ouds-web.scss @@ -19,7 +19,7 @@ @import "@ouds/web-common/scss/images"; @import "@ouds/web-common/scss/containers"; @import "@ouds/web-common/scss/grid"; -@import "@ouds/web-common/scss/tables"; +@import "@ouds/web-common/scss/table"; @import "@ouds/web-common/scss/forms"; @import "@ouds/web-common/scss/links"; // OUDS mod @import "@ouds/web-common/scss/bullet-list"; // OUDS mod From 9443d5a8f3a13664036810bf20660281daf26bb3 Mon Sep 17 00:00:00 2001 From: Hannah Issermann Date: Tue, 31 Mar 2026 18:50:57 +0200 Subject: [PATCH 08/22] Rich content --- scss/_mixins.scss | 1 - scss/_table.scss | 51 +++---- scss/_variables.scss | 17 +-- scss/mixins/_table-variants.scss | 25 ---- site/src/content/docs/components/table.mdx | 149 +++++++++++++++------ 5 files changed, 128 insertions(+), 115 deletions(-) delete mode 100644 scss/mixins/_table-variants.scss diff --git a/scss/_mixins.scss b/scss/_mixins.scss index aaf11695f0..42d9327b1c 100644 --- a/scss/_mixins.scss +++ b/scss/_mixins.scss @@ -30,7 +30,6 @@ @import "mixins/pagination"; @import "mixins/lists"; @import "mixins/forms"; -@import "mixins/table-variants"; // Skins @import "mixins/border-radius"; diff --git a/scss/_table.scss b/scss/_table.scss index 4b9de24265..29162e11bd 100644 --- a/scss/_table.scss +++ b/scss/_table.scss @@ -1,13 +1,13 @@ // // Basic OUDS Web table // -%row-selection { +%has-custom-item { width: calc($ouds-checkbox-size-min-width + $core-ouds-dimension-50); padding: 0; vertical-align: middle; } -%row-active { +%active { --#{$prefix}table-color-state: var(--#{$prefix}table-active-color); --#{$prefix}table-bg-state: var(--#{$prefix}table-active-bg); } @@ -21,7 +21,7 @@ // End of reset --#{$prefix}table-color: #{$table-color}; --#{$prefix}table-bg: #{$table-bg}; - --#{$prefix}table-border-color: #{$table-border-color}; // OK + --#{$prefix}table-border-color: #{$table-border-color}; --#{$prefix}table-accent-bg: #{$table-accent-bg}; --#{$prefix}table-striped-color: #{$table-striped-color}; --#{$prefix}table-striped-bg: #{$table-striped-bg}; @@ -81,21 +81,16 @@ // OUDS mod // When using checkboxes in the first column, force width to ensure correct spacing on this column - &.has-row-selection tr > :first-child { - @extend %row-selection; + tr > td:has(.control-item-indicator[type="checkbox"]), + tr > td:has(.control-item-indicator[type="radio"]) { + @extend %has-custom-item; } // Automatically highlight rows with checked checkboxes - &.has-row-selection tbody tr:has(.control-item-indicator[type="checkbox"]:not([role="switch"]):checked), - &.has-row-selection tbody tr:has(.control-item-indicator[type="radio"]:checked) { - @extend %row-active; - @extend [data-bs-theme=root-inverted]; - } - - @if $enable-bootstrap-compatibility { - &.has-checkbox tr > :first-child { - @extend %row-selection; - } + tbody tr:has(.control-item-indicator[type="checkbox"]:not([role="switch"]):checked), + tbody tr:has(.control-item-indicator[type="radio"]:checked) { + @extend %active; + @extend [data-bs-theme=dark]; } // Use negative margins on icons in tables to preserve row height @@ -119,18 +114,6 @@ caption-side: bottom; // OUDS mod } - -// -// Condensed table w/ half padding -// - -//.table-sm { -// // stylelint-disable-next-line selector-max-universal -// > :not(caption) > * > * { -// padding: $table-cell-padding-y-sm $table-cell-padding-x-sm calc($table-cell-padding-y-sm + 1px); // OUDS mod -// } -//} - // OUDS mod: no .table-bordered // OUDS mod: no .table-borderless @@ -166,7 +149,7 @@ // The `.table-active` class can be added to highlight rows or cells .table-active { - @extend %row-active; + @extend %active; } // Hover effect @@ -180,12 +163,12 @@ } } -// Table variants set the table cell backgrounds, border colors -// and the colors of the striped, hovered & active tables - -//@each $color, $value in $table-variants { -// @include table-variant($color, $value); -//} +// Table functional colors +@each $table-state in ("info", "positive", "warning", "negative") { + .table-#{$table-state} { + --#{$prefix}table-bg: var(--#{$prefix}color-surface-status-#{$table-state}-muted); + } +} // Responsive tables // diff --git a/scss/_variables.scss b/scss/_variables.scss index c1d1e2059a..271498ee63 100644 --- a/scss/_variables.scss +++ b/scss/_variables.scss @@ -809,7 +809,7 @@ $table-striped-bg-factor: .035 !default; // OUDS mod: equivalent t $table-striped-bg: var(--#{$prefix}color-bg-secondary) !default; // OUDS mod: instead of `rgba(var(--#{$prefix}emphasis-color-rgb), $table-striped-bg-factor)` $table-variant-striped-bg-factor: .08 !default; // OUDS mod -$table-active-color: var(--#{$prefix}color-content-inverse) !default; +$table-active-color: var(--#{$prefix}color-content-default) !default; $table-active-bg-factor: .135 !default; // OUDS mod $table-active-bg: var(--#{$prefix}color-bg-inverse-low) !default; // OUDS mod: instead of `rgba(var(--#{$prefix}emphasis-color-rgb), $table-active-bg-factor)` $table-variant-active-bg-factor: .4 !default; // OUDS mod @@ -831,23 +831,8 @@ $table-group-separator-color: currentcolor !default; $table-caption-color: var(--#{$prefix}caption-color, var(--#{$prefix}emphasis-color)) !default; // OUDS mod: instead of `var(--#{$prefix}secondary-color)` $table-caption-padding-y: .75rem !default; // OUDS mod - -$table-bg-scale: -60% !default; // scss-docs-end table-variables -// scss-docs-start table-loop -$table-variants: ( - "primary": shift-color($primary, $table-bg-scale), - "secondary": shift-color($secondary, $table-bg-scale), - "success": shift-color($success, $table-bg-scale), - "info": shift-color($info, $table-bg-scale), - "warning": shift-color($warning, $table-bg-scale), - "danger": shift-color($danger, $table-bg-scale), - "light": $light, - "dark": $dark, -) !default; -// scss-docs-end table-loop - // Buttons + Forms // // Shared variables that are reassigned to `$input-` and `$btn-` specific variables. diff --git a/scss/mixins/_table-variants.scss b/scss/mixins/_table-variants.scss deleted file mode 100644 index 035ae7923d..0000000000 --- a/scss/mixins/_table-variants.scss +++ /dev/null @@ -1,25 +0,0 @@ -// OUDS mod: Variants have a different hover and striped management -// scss-docs-start table-variant -@mixin table-variant($state, $background) { - .table-#{$state} { - $color: color-contrast(opaque($body-bg, $background)); - $hover-bg: mix($color, $background, percentage($table-variant-hover-bg-factor));// OUDS mod - $striped-bg: mix($color, $background, percentage($table-variant-striped-bg-factor)); // OUDS mod - $active-bg: mix($color, $background, percentage($table-variant-active-bg-factor)); // OUDS mod - $table-border-color: mix($color, $background, percentage($table-border-factor)); - - --#{$prefix}table-color: #{$color}; - --#{$prefix}table-bg: #{$background}; - --#{$prefix}table-border-color: #{$table-border-color}; - --#{$prefix}table-striped-bg: #{$striped-bg}; - --#{$prefix}table-striped-color: #{color-contrast($striped-bg)}; - --#{$prefix}table-active-bg: #{$active-bg}; - --#{$prefix}table-active-color: #{color-contrast($active-bg)}; - --#{$prefix}table-hover-bg: #{$hover-bg}; - --#{$prefix}table-hover-color: #{color-contrast($hover-bg)}; - - color: var(--#{$prefix}table-color); - border-color: var(--#{$prefix}table-border-color); - } -} -// scss-docs-end table-variant diff --git a/site/src/content/docs/components/table.mdx b/site/src/content/docs/components/table.mdx index 25d1f4a3d8..0213513e9c 100644 --- a/site/src/content/docs/components/table.mdx +++ b/site/src/content/docs/components/table.mdx @@ -8,6 +8,7 @@ toc: true --- import { getData } from '@libs/data' +import { getVersionedDocsPath } from '@libs/path' The table component is not yet designed, and this component is only a draft for the moment. It will be updated in the future with the final design and will certainly need adjustments regarding the DOM. Use it as a temporary component to speed up your development. @@ -60,6 +61,43 @@ See [more information about the tables structures](https://a11y-guidelines.orang ## Variants +### Functional colors + +To add a background color to a table row, you can use the contextual classes `.table-{status}` on `` elements. These classes will apply a muted background color based on the status you choose, among `info`, `positive`, `warning`, or `negative`. This can be useful for highlighting specific rows based on their content or status. Statuses could be emphasized further by adding a badge with the same color in the relevant cell(s), and with a relevant label. + + + OUDS Web table with functional colored backgrounds + + + # + Status + Heading + + + + + 1 +

Running + Cell + + + 2 +

New + Cell + + + 3 +

Reloading + Cell + + + 4 +

Error + Cell + + + `} /> + ### Zebra To create a striped table, add the `.table-zebra` modifier class to the base `.table` class. This will add a background color to even rows (not including the header) to improve readability. @@ -99,12 +137,10 @@ To create a striped table, add the `.table-zebra` modifier class to the base `.t ## Responsive tables -Responsive tables allow tables to be scrolled horizontally with ease. Make any table responsive across all viewports by wrapping a `.table` with `.table-responsive`. Or, pick a maximum breakpoint with which to have a responsive table up to by using `.table-responsive{-sm|-md|-lg|-xl|-xxl}`. - - - ##### Vertical clipping/truncation +Responsive tables allow tables to be scrolled horizontally with ease. Make any table responsive across all viewports by wrapping a `.table` with `.table-responsive`. Or, pick a maximum breakpoint with which to have a responsive table up to by using `.table-responsive{-xs|-sm|-md|-lg|-xl|-2xl|3xl}`. - Responsive tables make use of `overflow-y: hidden`, which clips off any content that goes beyond the bottom or top edges of the table. In particular, this can clip off dropdown menus and other third-party widgets. + +Responsive tables make use of `overflow-y: hidden`, which clips off any content that goes beyond the bottom or top edges of the table. In particular, this can clip off dropdown menus and other third-party widgets. ### Always responsive @@ -184,9 +220,11 @@ Use `.table-responsive{-xs|-sm|-md|-lg|-xl|-2xl|3xl}` as needed to create respon
Examples of responsive tables up to particular breakpoint +Resize window to see differencies: {getData('breakpoints').map((breakpoint) => { return (
+
@@ -256,7 +294,7 @@ return ( ### Row selection -When using checkboxes, radio buttons or switches in tables, you should add the `.has-row-selection` modifier class to the base `.table` class. This will add the necessary padding to the first column to accommodate these control items. The control items should be placed in the first column, and the type of control items should obviously not be mixed. +When using checkboxes or radio buttons or switches in tables, you should add the `.has-row-selection` modifier class to the base `.table` class. This will add the necessary padding to the first column to accommodate these control items. The control items should be placed in the first column, and the type of control items should obviously not be mixed. For the row selection purpose, you should use [standalone checkboxes]([[docsref:/components/checkbox#standalone]]), [standalone radio buttons]([[docsref:/components/radio-button#standalone]]), or [standalone switches]([[docsref:/components/switch#standalone]]) with `.visually-hidden` labels describing their use. @@ -264,48 +302,48 @@ If the control items are checkboxes, the first cell of the header should contain If the control items are checkboxes or radio buttons, selecting a row will automtically apply some styles to visually indicate that the row is selected. If you want to manually apply the same styles to rows or even cells, you can use the class `.table-active` on `` or ` - - - - @@ -315,7 +353,7 @@ If the control items are checkboxes or radio buttons, selecting a row will autom To manage checkboxes states (e.g., select/deselect all rows, update header checkbox state), here is an example of JavaScript code: - + @@ -326,77 +364,110 @@ To manage checkboxes states (e.g., select/deselect all rows, update header check - - -
Boosted responsive table for {breakpoint.abbr} breakpoint and under
` elements. - +
OUDS Web table with row selection
+ - + Heading Heading
+ - + Cell Cell
+ - + Cell Cell
+ - + Cell Cell
OUDS Web table with radio buttons
+ - + Cell Cell
+ - + Cell Cell
+ - + Cell Cell
`} /> - +### Additional content + +You can also use other components in tables, such as tags, switches, images or icons. You can use the `.align-middle` class on `` elements to vertically align the content of cells in the middle of the row, which is useful for rows with rich content. + + OUDS Web table with switches - Select Heading Heading + Heading + Activated - - + + + Cell + + Cell + +

+ + Maintenance +

+ + - - Cell - Cell + - - + + + Cell + + Cell + +

+ + Running +

+ + - - Cell - Cell + - - + + + Cell + + Cell + +

+ + Error +

+ + - - Cell - Cell + `} /> From ec0826e226762f119a88b70e4c3b180b70f9195d Mon Sep 17 00:00:00 2001 From: Hannah Issermann Date: Thu, 2 Apr 2026 15:32:59 +0200 Subject: [PATCH 09/22] rollback snippets --- site/src/assets/partials/snippets.js | 54 ++++++++++++++-------------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/site/src/assets/partials/snippets.js b/site/src/assets/partials/snippets.js index efccd4c1ad..849beb8ef9 100644 --- a/site/src/assets/partials/snippets.js +++ b/site/src/assets/partials/snippets.js @@ -198,36 +198,37 @@ export default () => { // ------------------------------- // First example // js-docs-start skeleton-first-example + const skeletonToReplace = document.querySelector('.bd-skeleton-replace') + const originalContent = skeletonToReplace.innerHTML + function replaceSkeleton() { setTimeout(() => { skeletonToReplace.innerHTML = `
- -
-

Placeholder title

-

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nec risus et risus consectetur dignissim volutpat ut lorem. Aenean posuere elementum massa, ac elementum magna auctor quis. Aliquam erat volutpat. Ut quam turpis, interdum non ex at, imperdiet ornare mi.

-
+ +
+

Placeholder title

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nec risus et risus consectetur dignissim volutpat ut lorem. Aenean posuere elementum massa, ac elementum magna auctor quis. Aliquam erat volutpat. Ut quam turpis, interdum non ex at, imperdiet ornare mi.

- - ` +
+ + ` }, 8000) } - const skeletonToReplace = document.querySelector('.bd-skeleton-replace') - if (skeletonToReplace) { - const originalContent = skeletonToReplace.innerHTML - document.addEventListener('DOMContentLoaded', () => { - replaceSkeleton() - }) + document.addEventListener('DOMContentLoaded', () => { + replaceSkeleton() + }) - window.relaunchAnim = () => { - skeletonToReplace.innerHTML = originalContent - replaceSkeleton() - } + window.relaunchAnim = () => { + skeletonToReplace.innerHTML = originalContent + replaceSkeleton() } // js-docs-end skeleton-first-example // Second example // js-docs-start skeleton-second-example + const skeletonToReplace2 = document.querySelector('.bd-skeleton-replace2') + function removeSkeletons() { setTimeout(() => { skeletonToReplace2.firstElementChild.removeAttribute('inert') @@ -236,18 +237,15 @@ export default () => { }, 8000) } - const skeletonToReplace2 = document.querySelector('.bd-skeleton-replace2') - if (skeletonToReplace2) { - document.addEventListener('DOMContentLoaded', () => { - removeSkeletons() - }) + document.addEventListener('DOMContentLoaded', () => { + removeSkeletons() + }) - window.relaunchAnim2 = () => { - skeletonToReplace2.firstElementChild.setAttribute('inert', '') - skeletonToReplace2.firstElementChild.setAttribute('aria-busy', 'true') - skeletonToReplace2.lastElementChild.textContent = 'Loading form ...' - removeSkeletons() - } + window.relaunchAnim2 = () => { + skeletonToReplace2.firstElementChild.setAttribute('inert', '') + skeletonToReplace2.firstElementChild.setAttribute('aria-busy', 'true') + skeletonToReplace2.lastElementChild.textContent = 'Loading form ...' + removeSkeletons() } // js-docs-end skeleton-second-example From 38564932222d61fd8a15fa72c89c97c43d89df9a Mon Sep 17 00:00:00 2001 From: Hannah Issermann Date: Thu, 2 Apr 2026 15:35:22 +0200 Subject: [PATCH 10/22] remove has-row-selection selector --- site/src/assets/partials/snippets.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/site/src/assets/partials/snippets.js b/site/src/assets/partials/snippets.js index 849beb8ef9..802862075e 100644 --- a/site/src/assets/partials/snippets.js +++ b/site/src/assets/partials/snippets.js @@ -256,11 +256,11 @@ export default () => { // storybook-start table // js-docs-start live-row-selection // Manage checkboxes states (e.g., select/deselect all rows, update header checkbox state) - const tableSelectAll = document.querySelector('.has-row-selection#tableWithCheckboxes #tableSelectAll') - const allCheckboxes = document.querySelectorAll('.has-row-selection#tableWithCheckboxes tbody input[type="checkbox"]') + const tableSelectAll = document.querySelector('#tableWithCheckboxes #tableSelectAll') + const allCheckboxes = document.querySelectorAll('#tableWithCheckboxes tbody input[type="checkbox"]') function updateSelectAllState() { - const checkedCheckboxes = document.querySelectorAll('.has-row-selection#tableWithCheckboxes tbody input[type="checkbox"]:checked') + const checkedCheckboxes = document.querySelectorAll('#tableWithCheckboxes tbody input[type="checkbox"]:checked') if (checkedCheckboxes.length === 0) { // None are checked From caec4f08d958b851762d6fe44a4a554b6706865c Mon Sep 17 00:00:00 2001 From: Hannah Issermann Date: Thu, 9 Apr 2026 15:49:57 +0200 Subject: [PATCH 11/22] refactor(tables): Improve checkbox and radio button selection handling in tables --- scss/_table.scss | 35 ++++++------- site/src/assets/partials/snippets.js | 48 ++++++++++++++++-- site/src/content/docs/components/table.mdx | 58 ++++++++++++++++------ 3 files changed, 102 insertions(+), 39 deletions(-) diff --git a/scss/_table.scss b/scss/_table.scss index 29162e11bd..b90463bfb4 100644 --- a/scss/_table.scss +++ b/scss/_table.scss @@ -1,16 +1,6 @@ // // Basic OUDS Web table // -%has-custom-item { - width: calc($ouds-checkbox-size-min-width + $core-ouds-dimension-50); - padding: 0; - vertical-align: middle; -} - -%active { - --#{$prefix}table-color-state: var(--#{$prefix}table-active-color); - --#{$prefix}table-bg-state: var(--#{$prefix}table-active-bg); -} .table { // Reset needed for nesting tables @@ -82,15 +72,26 @@ // OUDS mod // When using checkboxes in the first column, force width to ensure correct spacing on this column tr > td:has(.control-item-indicator[type="checkbox"]), - tr > td:has(.control-item-indicator[type="radio"]) { - @extend %has-custom-item; + tr > th:has(.control-item-indicator[type="checkbox"]), + tr > td:has(.control-item-indicator[type="radio"]), + tr > th:has(.control-item-indicator[type="radio"]) { + width: calc($ouds-checkbox-size-min-width + $core-ouds-dimension-50); + padding: 0; + vertical-align: middle; } - // Automatically highlight rows with checked checkboxes + // Extend checkboxes and radios click area + tr .radio-button-standalone, + tr .checkbox-standalone, + tr .switch-standalone { + width: stretch; + } + + // Automatically highlight rows with checked checkboxes or radios tbody tr:has(.control-item-indicator[type="checkbox"]:not([role="switch"]):checked), tbody tr:has(.control-item-indicator[type="radio"]:checked) { - @extend %active; - @extend [data-bs-theme=dark]; + --#{$prefix}table-color-state: var(--#{$prefix}color-content-default); + --#{$prefix}table-bg-state: var(--#{$prefix}table-active-bg); } // Use negative margins on icons in tables to preserve row height @@ -148,10 +149,6 @@ // // The `.table-active` class can be added to highlight rows or cells -.table-active { - @extend %active; -} - // Hover effect // // Placed here since it has to come after the potential zebra striping diff --git a/site/src/assets/partials/snippets.js b/site/src/assets/partials/snippets.js index cb01d4969f..067f26ebec 100644 --- a/site/src/assets/partials/snippets.js +++ b/site/src/assets/partials/snippets.js @@ -258,8 +258,8 @@ export default () => { // ------------------------------- // Indeterminate checkbox in table example in docs and StackBlitz // storybook-start table - // js-docs-start live-row-selection - // Manage checkboxes states (e.g., select/deselect all rows, update header checkbox state) + // js-docs-start live-row-selection-checkboxes + // Manage checkboxes states: select/deselect all rows, update header checkbox state, update data-bs-theme on selected rows const tableSelectAll = document.querySelector('#tableWithCheckboxes #tableSelectAll') const allCheckboxes = document.querySelectorAll('#tableWithCheckboxes tbody input[type="checkbox"]') @@ -281,22 +281,60 @@ export default () => { } } + function updateSelectedRows() { + const selectedRows = document.querySelectorAll('#tableWithCheckboxes tbody tr:has(input[type="checkbox"]:checked)') + + if (selectedRows.length >= 1) { + selectedRows.forEach(row => row.setAttribute('data-bs-theme', 'dark')) + } + + const unselectedRows = document.querySelectorAll('#tableWithCheckboxes tbody tr:has(input[type="checkbox"]:not(:checked))') + if (unselectedRows.length >= 1) { + unselectedRows.forEach(row => row.removeAttribute('data-bs-theme')) + } + + updateSelectAllState() + } + if (tableSelectAll) { tableSelectAll.addEventListener('change', event => { allCheckboxes.forEach(checkbox => { checkbox.checked = event.target.checked }) - updateSelectAllState() + updateSelectedRows() }) // Add change listener to all row checkboxes allCheckboxes.forEach(checkbox => { - checkbox.addEventListener('change', updateSelectAllState) + checkbox.addEventListener('change', updateSelectedRows) }) // Initialize the state on load updateSelectAllState() } - // js-docs-end live-row-selection + // js-docs-end live-row-selection-checkboxes + + // js-docs-start live-row-selection-radios + // Manage radio buttons states: update data-bs-theme on selected row + const allRadios = document.querySelectorAll('#tableWithRadios tbody input[type="radio"]') + // Add change listener to all row radios + allRadios.forEach(radio => { + radio.addEventListener('change', event => { + const selectedRow = event.target.closest('tr') + const allRows = document.querySelectorAll('#tableWithRadios tbody tr') + + // Remove data-bs-theme from all rows + allRows.forEach(row => row.removeAttribute('data-bs-theme')) + + // Add data-bs-theme="dark" to the selected row + if (selectedRow) { + selectedRow.setAttribute('data-bs-theme', 'dark') + } + }) + }) + // js-docs-end live-row-selection-radios + // storybook-end table + + } diff --git a/site/src/content/docs/components/table.mdx b/site/src/content/docs/components/table.mdx index 0213513e9c..34cc46a706 100644 --- a/site/src/content/docs/components/table.mdx +++ b/site/src/content/docs/components/table.mdx @@ -220,7 +220,7 @@ Use `.table-responsive{-xs|-sm|-md|-lg|-xl|-2xl|3xl}` as needed to create respon
Examples of responsive tables up to particular breakpoint -Resize window to see differencies: +Resize window to see differences: {getData('breakpoints').map((breakpoint) => { return (
@@ -300,24 +300,26 @@ For the row selection purpose, you should use [standalone checkboxes]([[docsref: If the control items are checkboxes, the first cell of the header should contain a checkbox to select or deselect all rows. If some rows are selected, the header checkbox should be in an [indeterminate state]([[docsref:/components/checkbox#indeterminate]]) to indicate this. -If the control items are checkboxes or radio buttons, selecting a row will automtically apply some styles to visually indicate that the row is selected. If you want to manually apply the same styles to rows or even cells, you can use the class `.table-active` on `` or `` elements. +If the control items are checkboxes or radio buttons, selecting a row will automatically apply some styles to visually indicate that the row is selected. If you want to manually apply the same styles to rows or even cells, you can use the class `.table-active` on `` or `` elements. + +Note that the click area will be extended to the full width of the cell. OUDS Web table with row selection - + - + Heading Heading - +
-## Rich content tables - -### Row selection +## Row selection -When using checkboxes or radio buttons or switches in tables, you should add the `.has-row-selection` modifier class to the base `.table` class. This will add the necessary padding to the first column to accommodate these control items. The control items should be placed in the first column, and the type of control items should obviously not be mixed. +### With checkboxes -For the row selection purpose, you should use [standalone checkboxes]([[docsref:/components/checkbox#standalone]]), [standalone radio buttons]([[docsref:/components/radio-button#standalone]]), or [standalone switches]([[docsref:/components/switch#standalone]]) with `.visually-hidden` labels describing their use. +For the row selection purpose, you should use [standalone checkboxes]([[docsref:/components/checkbox#standalone]]) with `.visually-hidden` labels describing their use. -If the control items are checkboxes, the first cell of the header should contain a checkbox to select or deselect all rows. If some rows are selected, the header checkbox should be in an [indeterminate state]([[docsref:/components/checkbox#indeterminate]]) to indicate this. +The first cell of the header should contain a checkbox to select or deselect all rows. When some rows - but not all - are selected, the header checkbox should be in an [indeterminate state]([[docsref:/components/checkbox#indeterminate]]). -If the control items are checkboxes or radio buttons, selecting a row will automatically apply some styles to visually indicate that the row is selected. If you want to manually apply the same styles to rows or even cells, you can use the class `.table-active` on `` or `` elements. +To visually indicate a row is selected, you'll need to apply a `data-bs-theme="dark"` attribute on the `` element (some additional styles will be applied too). This can be done by JavaScript, see the example below. If you want to manually apply the same styles to rows or even cells, you can use the class `.table-active` with `data-bs-theme="dark"` on `` or `` elements. -Note that the click area will be extended to the full width of the cell. +Note that the width of columns containing checkboxes will automatically adjust to the largest cell, and the click area will be extended to the full width of the cell. OUDS Web table with row selection @@ -352,9 +350,15 @@ Note that the click area will be extended to the full width of the cell. `} /> -To manage checkboxes states (i.e. select/deselect all rows, update header checkbox state, and update data-bs-theme on selected row), here is an example of JavaScript code: +To manage checkboxes states and active styles (i.e. select/deselect all rows, update header checkbox state, and update `data-bs-theme` on selected row), here is an example of JavaScript code: +### With radio buttons + +For the row selection purpose, you should use [standalone radio buttons]([[docsref:/components/radio-button#standalone]]) with `.visually-hidden` labels describing their use. + +The [same rules apply as with checkboxes](#with-checkboxes), except that there is no "all rows" selection. The JavaScript will only need to update the `data-bs-theme` on selected rows, as we have done in the example below. + OUDS Web table with radio buttons @@ -398,17 +402,15 @@ To manage checkboxes states (i.e. select/deselect all rows, update header checkb `} /> -To manage radio buttons states (i.e. update data-bs-theme on selected row), here is an example of JavaScript code: - +To manage radio buttons active state (i.e. update `data-bs-theme` on the selected row), here is an example of JavaScript code: + -### Other components +## Rich content tables -You can also use other components in tables, such as tags, switches, images or icons. You can use the `.align-middle` class on `` elements to vertically align the content of cells in the middle of the row, which is useful for rows with rich content. +You can also use other components in tables, such as tags, badges, switches, images or icons. You can use the `.align-middle` class on `` elements to vertically align the content of cells in the middle of the row, which is useful for rows with rich content. The class `.text-center` can be used on `` and `` elements to center the content of the cell horizontally when needed. For switches, note that the click area will be extended to the full width of the cell. -The class `.text-center` can be used on `` and `` elements to center the content of the cell horizontally when needed. - OUDS Web table with switches From 375ce83534a516bf7e555715cf613d6ae15840e9 Mon Sep 17 00:00:00 2001 From: Hannah Issermann Date: Wed, 15 Apr 2026 10:16:55 +0200 Subject: [PATCH 14/22] Test CI --- site/src/content/docs/components/table.mdx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/site/src/content/docs/components/table.mdx b/site/src/content/docs/components/table.mdx index 58b88e8c12..b9bc61e26f 100644 --- a/site/src/content/docs/components/table.mdx +++ b/site/src/content/docs/components/table.mdx @@ -218,8 +218,7 @@ Use `.table-responsive{-xs|-sm|-md|-lg|-xl|-2xl|3xl}` as needed to create respon **These tables may appear broken until their responsive styles apply at specific viewport widths.** -
-Examples of responsive tables up to particular breakpoint +
Examples of responsive tables up to particular breakpoint Resize window to see differences: {getData('breakpoints').map((breakpoint) => { return ( From dfb6ca348c4c4f95f3c72df651dd78fb218b90b5 Mon Sep 17 00:00:00 2001 From: Hannah Issermann Date: Wed, 15 Apr 2026 10:37:01 +0200 Subject: [PATCH 15/22] Test CI --- site/src/content/docs/components/table.mdx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/site/src/content/docs/components/table.mdx b/site/src/content/docs/components/table.mdx index b9bc61e26f..58b88e8c12 100644 --- a/site/src/content/docs/components/table.mdx +++ b/site/src/content/docs/components/table.mdx @@ -218,7 +218,8 @@ Use `.table-responsive{-xs|-sm|-md|-lg|-xl|-2xl|3xl}` as needed to create respon **These tables may appear broken until their responsive styles apply at specific viewport widths.** -
Examples of responsive tables up to particular breakpoint +
+Examples of responsive tables up to particular breakpoint Resize window to see differences: {getData('breakpoints').map((breakpoint) => { return ( From 1aef4f56ff0592d2ba5ecbd08ca861f7904ae2e3 Mon Sep 17 00:00:00 2001 From: Hannah Issermann Date: Wed, 15 Apr 2026 11:47:48 +0200 Subject: [PATCH 16/22] Test CI --- site/src/content/docs/components/table.mdx | 132 ++++++++++----------- site/src/types/auto-import.d.ts | 1 + 2 files changed, 66 insertions(+), 67 deletions(-) diff --git a/site/src/content/docs/components/table.mdx b/site/src/content/docs/components/table.mdx index 58b88e8c12..2b739d9847 100644 --- a/site/src/content/docs/components/table.mdx +++ b/site/src/content/docs/components/table.mdx @@ -218,77 +218,75 @@ Use `.table-responsive{-xs|-sm|-md|-lg|-xl|-2xl|3xl}` as needed to create respon **These tables may appear broken until their responsive styles apply at specific viewport widths.** -
-Examples of responsive tables up to particular breakpoint -Resize window to see differences: -{getData('breakpoints').map((breakpoint) => { -return ( -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Boosted responsive table for {breakpoint.abbr} breakpoint and under
#HeadingHeadingHeadingHeadingHeadingHeadingHeadingHeading
1CellCellCellCellCellCellCellCell
2CellCellCellCellCellCellCellCell
3CellCellCellCellCellCellCellCell
-
-
-) -})} - - `
+
+ Resize window to see differences: + {getData('breakpoints').map((breakpoint) => { + return ( +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Boosted responsive table for {breakpoint.abbr} breakpoint and under
#HeadingHeadingHeadingHeadingHeadingHeadingHeadingHeading
1CellCellCellCellCellCellCellCell
2CellCellCellCellCellCellCellCell
3CellCellCellCellCellCellCellCell
+
+
+ ) + })} + + `
...
`)} /> - -
+
## Row selection diff --git a/site/src/types/auto-import.d.ts b/site/src/types/auto-import.d.ts index 45a7b0c06e..bcc5b56c85 100644 --- a/site/src/types/auto-import.d.ts +++ b/site/src/types/auto-import.d.ts @@ -15,6 +15,7 @@ export declare global { export const Code: typeof import('@shortcodes/Code.astro').default export const ComponentCard: typeof import('@shortcodes/ComponentCard.astro').default export const DeprecatedIn: typeof import('@shortcodes/DeprecatedIn.astro').default + export const Details: typeof import('@shortcodes/Details.astro').default export const EnableBtnCloseTooltip: typeof import('@shortcodes/EnableBtnCloseTooltip.astro').default export const Example: typeof import('@shortcodes/Example.astro').default export const JsDismiss: typeof import('@shortcodes/JsDismiss.astro').default From d991f7ba22919ff5ee86b97d390a6fa71aa0bdd2 Mon Sep 17 00:00:00 2001 From: Hannah Issermann Date: Wed, 15 Apr 2026 11:48:17 +0200 Subject: [PATCH 17/22] Test CI --- site/src/components/shortcodes/Details.astro | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 site/src/components/shortcodes/Details.astro diff --git a/site/src/components/shortcodes/Details.astro b/site/src/components/shortcodes/Details.astro new file mode 100644 index 0000000000..23a5cf273f --- /dev/null +++ b/site/src/components/shortcodes/Details.astro @@ -0,0 +1,15 @@ +--- +/* + * Outputs details element + */ +interface Props { + summary: string +} + +const { summary } = Astro.props +--- + +
+ {summary} + +
From 35edd78b121ce57e8b35074587f17e26ca9be375 Mon Sep 17 00:00:00 2001 From: Hannah Issermann Date: Wed, 15 Apr 2026 14:36:48 +0200 Subject: [PATCH 18/22] Update site/src/content/docs/components/table.mdx Co-authored-by: Maxime Lardenois --- site/src/content/docs/components/table.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/src/content/docs/components/table.mdx b/site/src/content/docs/components/table.mdx index 2b739d9847..6362825a38 100644 --- a/site/src/content/docs/components/table.mdx +++ b/site/src/content/docs/components/table.mdx @@ -18,7 +18,7 @@ import { getVersionedDocsPath } from '@libs/path' ## Overview -Due to the extensive use of `` elements in third-party widgets such as calendars and date pickers, OUDS Web’s tables are **opt-in**. This means that you must add the base class `.table` to any `
`, to benefit from OUDS Web's table styles which you can then extend with our optional modifier classes or custom styles. All table styles are not inherited in OUDS Web, meaning any nested tables can be styled independent of the parent. +Due to the extensive use of `
` elements in third-party widgets such as calendars and date pickers, OUDS Web’s tables are **opt-in**. This means that you must add the base class `.table` to any `
`, to benefit from OUDS Web's table styles which you can then extend with our optional modifier classes or custom styles. In OUDS Web, table styles are not inherited, enabling independent styling for nested tables. Using the most basic table markup, here’s how `.table`-based tables look in OUDS Web. From 46201dcd1c96a7c70ce394ba50f49d11eacb32e3 Mon Sep 17 00:00:00 2001 From: Hannah Issermann Date: Wed, 15 Apr 2026 15:41:26 +0200 Subject: [PATCH 19/22] enhancements after 1st review --- scss/_table.scss | 8 +----- site/src/components/shortcodes/Details.astro | 2 +- site/src/content/docs/components/table.mdx | 27 +++++++++++++------- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/scss/_table.scss b/scss/_table.scss index a0ee6e3c17..d6e5c21305 100644 --- a/scss/_table.scss +++ b/scss/_table.scss @@ -118,19 +118,13 @@ // Default zebra-stripe styles (alternating gray and transparent backgrounds) // For rows -.table-zebra { +.table-striped { > tbody > tr:nth-of-type(#{$table-striped-order}) > * { --#{$prefix}table-color-type: var(--#{$prefix}table-striped-color); --#{$prefix}table-bg-type: var(--#{$prefix}table-striped-bg); } } -@if $enable-bootstrap-compatibility { - .table-striped { - @extend .table-zebra; - } -} - // For columns .table-striped-columns { > :not(caption) > tr > :nth-child(#{$table-striped-columns-order}) { diff --git a/site/src/components/shortcodes/Details.astro b/site/src/components/shortcodes/Details.astro index 23a5cf273f..799cc54eee 100644 --- a/site/src/components/shortcodes/Details.astro +++ b/site/src/components/shortcodes/Details.astro @@ -1,6 +1,6 @@ --- /* - * Outputs details element + * Outputs a detail element, with the specified summary while keeping the content of the details uninterpreted */ interface Props { summary: string diff --git a/site/src/content/docs/components/table.mdx b/site/src/content/docs/components/table.mdx index 6362825a38..f9939357ca 100644 --- a/site/src/content/docs/components/table.mdx +++ b/site/src/content/docs/components/table.mdx @@ -1,6 +1,6 @@ --- title: Table -description: Documentation and examples for opt-in styling of tables (given their prevalent use in JavaScript plugins) with OUDS Web. +description: Documentation and examples for opt-in styling of tables with OUDS Web. aliases: - "/docs/content/tables/" - "/docs/components/table/" @@ -13,7 +13,7 @@ import { getVersionedDocsPath } from '@libs/path' The table component is not yet designed, and this component is only a draft for the moment. It will be updated in the future with the final design and will certainly need adjustments regarding the DOM. Use it as a temporary component to speed up your development. - Please refer to the [Tables in the Boosted documentation](https://boosted.orange.com/docs/content/tables/) to have a full view of the table component and its variations. You’ll only need to adapt the utilities inside the DOM. + Please refer to the [Tables in the Boosted documentation](https://boosted.orange.com/docs/content/tables/) to have a full view of the table component and its variations. ## Overview @@ -98,11 +98,11 @@ To add a background color to a table row, you can use the contextual classes `.t
`} /> -### Zebra +### Striped rows -To create a striped table, add the `.table-zebra` modifier class to the base `.table` class. This will add a background color to even rows (not including the header) to improve readability. +Use `.table-striped` to add zebra-striping to any table row within the ``. This will add a background color to even rows (excluding the header) to improve readability. - + OUDS Web zebra table @@ -219,6 +219,7 @@ Use `.table-responsive{-xs|-sm|-md|-lg|-xl|-2xl|3xl}` as needed to create respon **These tables may appear broken until their responsive styles apply at specific viewport widths.**
+
Resize window to see differences: {getData('breakpoints').map((breakpoint) => { return ( @@ -292,7 +293,7 @@ Use `.table-responsive{-xs|-sm|-md|-lg|-xl|-2xl|3xl}` as needed to create respon ### With checkboxes -For the row selection purpose, you should use [standalone checkboxes]([[docsref:/components/checkbox#standalone]]) with `.visually-hidden` labels describing their use. +For the row selection purpose with checkboxes, you should use [standalone checkboxes]([[docsref:/components/checkbox#standalone]]) with `.visually-hidden` labels describing their use. The first cell of the header should contain a checkbox to select or deselect all rows. When some rows - but not all - are selected, the header checkbox should be in an [indeterminate state]([[docsref:/components/checkbox#indeterminate]]). @@ -353,7 +354,7 @@ To manage checkboxes states and active styles (i.e. select/deselect all rows, up ### With radio buttons -For the row selection purpose, you should use [standalone radio buttons]([[docsref:/components/radio-button#standalone]]) with `.visually-hidden` labels describing their use. +For the row selection purpose with radio buttons, you should use [standalone radio buttons]([[docsref:/components/radio-button#standalone]]) with `.visually-hidden` labels describing their use. The [same rules apply as with checkboxes](#with-checkboxes), except that there is no "all rows" selection. The JavaScript will only need to update the `data-bs-theme` on selected rows, as we have done in the example below. @@ -405,9 +406,9 @@ To manage radio buttons active state (i.e. update `data-bs-theme` on the selecte ## Rich content tables -You can also use other components in tables, such as tags, badges, switches, images or icons. You can use the `.align-middle` class on `` elements to vertically align the content of cells in the middle of the row, which is useful for rows with rich content. The class `.text-center` can be used on `` and `` elements to center the content of the cell horizontally when needed. +You can also use other components in tables, such as tags, badges, switches, images or icons. -For switches, note that the click area will be extended to the full width of the cell. +For standalone switches in tables, note that the click area will be extended to the full width of the cell. OUDS Web table with switches @@ -499,3 +500,11 @@ For switches, note that the click area will be extended to the full width of the `} /> + +### Layout + +To align horizontally or vertically, you can use the following: +- For horizontal alignment, use the `.text-center` class on `` and `` elements. +- For vertical alignment, use the `align-middle` class on the ``, `` and `` elements, or even on components within the cells themselves. + +These classes have been used in the examples above. From 679dc87baadc070f4d151a813a60374617048e8b Mon Sep 17 00:00:00 2001 From: Hannah Issermann Date: Wed, 15 Apr 2026 17:07:05 +0200 Subject: [PATCH 20/22] Improve rich content tables alignment --- scss/_table.scss | 18 +++- scss/_variables.scss | 4 +- site/src/content/docs/components/table.mdx | 115 +++++++++++++++++++-- 3 files changed, 122 insertions(+), 15 deletions(-) diff --git a/scss/_table.scss b/scss/_table.scss index d6e5c21305..1c26f770ff 100644 --- a/scss/_table.scss +++ b/scss/_table.scss @@ -75,8 +75,10 @@ // OUDS mod // When using checkboxes in the first column, force width to ensure correct spacing on this column - tr > td:has(.control-item-indicator), - tr > th:has(.control-item-indicator) { + tr > td:has(.control-item-indicator[type="checkbox"]:not([role="switch"])), + tr > td:has(.control-item-indicator[type="radio"]), + tr > th:has(.control-item-indicator[type="checkbox"]:not([role="switch"])), + tr > th:has(.control-item-indicator[type="radio"]) { width: 1%; padding: 0; vertical-align: middle; @@ -94,6 +96,18 @@ tbody tr:has(.control-item-indicator[type="radio"]:checked) { @extend %active; } + + // Use negative margins on icons in tables to preserve row height + svg, + img { + margin-top: $table-cell-icon-margin-top; + margin-bottom: $table-cell-icon-margin-bottom; + } + + .table-cell-component { + padding-block: 0; + vertical-align: middle; + } // End mod } diff --git a/scss/_variables.scss b/scss/_variables.scss index 35035899f1..df5cc897b5 100644 --- a/scss/_variables.scss +++ b/scss/_variables.scss @@ -791,8 +791,8 @@ $mark-bg: $ouds-color-action-highlighted-light !default; // $table-cell-padding-y: $core-ouds-dimension-200 !default; // OUDS mod $table-cell-padding-x: $core-ouds-dimension-200 !default; // OUDS mod -$table-cell-icon-margin-top: -.75rem !default; // OUDS mod -$table-cell-icon-margin-bottom: -.625rem !default; // OUDS mod +$table-cell-icon-margin-top: -.7rem !default; // OUDS mod +$table-cell-icon-margin-bottom: -.5rem !default; // OUDS mod $table-cell-vertical-align: top !default; $table-line-height: 1.25 !default; // OUDS mod diff --git a/site/src/content/docs/components/table.mdx b/site/src/content/docs/components/table.mdx index f9939357ca..28fd84c5d7 100644 --- a/site/src/content/docs/components/table.mdx +++ b/site/src/content/docs/components/table.mdx @@ -410,8 +410,12 @@ You can also use other components in tables, such as tags, badges, switches, ima For standalone switches in tables, note that the click area will be extended to the full width of the cell. - - OUDS Web table with switches +To align horizontally or vertically, you can use the following: +- For horizontal alignment, use the `.text-center` class on `` and `` elements. +- For vertical alignment, use the `.align-middle` class on the `` elements. + + + OUDS Web table with components and icons Heading @@ -428,7 +432,7 @@ For standalone switches in tables, note that the click area will be extended to Cell - Cell + Much longer cell content which wraps to another line to show the vertical alignment

@@ -436,7 +440,7 @@ For standalone switches in tables, note that the click area will be extended to

-

+

Warning

@@ -460,7 +464,7 @@ For standalone switches in tables, note that the click area will be extended to

-

+

OK

@@ -486,7 +490,7 @@ For standalone switches in tables, note that the click area will be extended to

-

+

Error

@@ -501,10 +505,99 @@ For standalone switches in tables, note that the click area will be extended to `} /> -### Layout -To align horizontally or vertically, you can use the following: -- For horizontal alignment, use the `.text-center` class on `` and `` elements. -- For vertical alignment, use the `align-middle` class on the ``, `` and `` elements, or even on components within the cells themselves. +### Row height and alignment + +To align vertically and preserve the row height, use the `.align-middle` class on the `` elements and `.table-cell-component` on `` elements containing components that could cause vertical overflow. + + + OUDS Web table with components and icons preserving the row height + + + Heading + Heading + Heading + Heading + Activated + + + + + + Cell + + Much longer cell content which wraps to another line to show the vertical alignment + +

+ + Maintenance +

+ + +

+ + Warning +

+ + + + + + + + Cell + + Cell + +

+ + Running +

+ + +

+ + OK +

+ + + + + + + + Cell + + Cell + +

+ + Error +

+ + +

+ + Error +

+ + + + + + + `} /> -These classes have been used in the examples above. From d77797bac26a838158dad54b1e24314446d6f917 Mon Sep 17 00:00:00 2001 From: Hannah Issermann Date: Thu, 16 Apr 2026 11:28:32 +0200 Subject: [PATCH 21/22] Refactor table styles and enhance content for better alignment --- scss/_table.scss | 7 +++++-- site/src/content/docs/components/table.mdx | 22 ++++++++++++++-------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/scss/_table.scss b/scss/_table.scss index 1c26f770ff..53a098dd2b 100644 --- a/scss/_table.scss +++ b/scss/_table.scss @@ -86,8 +86,7 @@ // Extend checkboxes and radios click area tr .radio-button-standalone, - tr .checkbox-standalone, - tr .switch-standalone { + tr .checkbox-standalone { width: stretch; } @@ -107,6 +106,10 @@ .table-cell-component { padding-block: 0; vertical-align: middle; + + > * { + vertical-align: middle; + } } // End mod } diff --git a/site/src/content/docs/components/table.mdx b/site/src/content/docs/components/table.mdx index 28fd84c5d7..89119397c9 100644 --- a/site/src/content/docs/components/table.mdx +++ b/site/src/content/docs/components/table.mdx @@ -313,6 +313,7 @@ Note that the width of columns containing checkboxes will automatically adjust t Heading Heading + Heading @@ -325,6 +326,7 @@ Note that the width of columns containing checkboxes will automatically adjust t Cell Cell + Cell @@ -333,6 +335,7 @@ Note that the width of columns containing checkboxes will automatically adjust t Select row 2 + This is a much longer section of text that demonstrates what happens when text wraps within a cell in a table Cell Cell @@ -345,6 +348,7 @@ Note that the width of columns containing checkboxes will automatically adjust t Cell Cell + Cell `} /> @@ -365,6 +369,7 @@ The [same rules apply as with checkboxes](#with-checkboxes), except that there i Select Heading Heading + Heading @@ -375,6 +380,7 @@ The [same rules apply as with checkboxes](#with-checkboxes), except that there i Select row 1 + This is a much longer section of text that demonstrates what happens when text wraps within a cell in a table Cell Cell @@ -387,6 +393,7 @@ The [same rules apply as with checkboxes](#with-checkboxes), except that there i Cell Cell + Cell @@ -397,6 +404,7 @@ The [same rules apply as with checkboxes](#with-checkboxes), except that there i Cell Cell + Cell `} /> @@ -408,11 +416,9 @@ To manage radio buttons active state (i.e. update `data-bs-theme` on the selecte You can also use other components in tables, such as tags, badges, switches, images or icons. -For standalone switches in tables, note that the click area will be extended to the full width of the cell. - To align horizontally or vertically, you can use the following: - For horizontal alignment, use the `.text-center` class on `` and `` elements. -- For vertical alignment, use the `.align-middle` class on the `` elements. +- For vertical alignment, use the `.align-middle` class on the `` elements. Some components inside cells may require additional alignment (possibly via a utility class). OUDS Web table with components and icons @@ -432,7 +438,7 @@ To align horizontally or vertically, you can use the following: Cell - Much longer cell content which wraps to another line to show the vertical alignment + This is a much longer section of text that demonstrates what happens when text wraps within a cell in a table

@@ -528,7 +534,7 @@ To align vertically and preserve the row height, use the `.align-middle` class o Cell - Much longer cell content which wraps to another line to show the vertical alignment + This is a much longer section of text that demonstrates what happens when text wraps within a cell in a table

@@ -536,7 +542,7 @@ To align vertically and preserve the row height, use the `.align-middle` class o

-

+

Warning

@@ -560,7 +566,7 @@ To align vertically and preserve the row height, use the `.align-middle` class o

-

+

OK

@@ -586,7 +592,7 @@ To align vertically and preserve the row height, use the `.align-middle` class o

-

+

Error

From 3f68f9c4a9d7c811bbac3d7baf928ec727b0393b Mon Sep 17 00:00:00 2001 From: Hannah Issermann Date: Thu, 16 Apr 2026 14:18:23 +0200 Subject: [PATCH 22/22] factorize css selectors --- scss/_table.scss | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/scss/_table.scss b/scss/_table.scss index 53a098dd2b..e692011c36 100644 --- a/scss/_table.scss +++ b/scss/_table.scss @@ -75,10 +75,7 @@ // OUDS mod // When using checkboxes in the first column, force width to ensure correct spacing on this column - tr > td:has(.control-item-indicator[type="checkbox"]:not([role="switch"])), - tr > td:has(.control-item-indicator[type="radio"]), - tr > th:has(.control-item-indicator[type="checkbox"]:not([role="switch"])), - tr > th:has(.control-item-indicator[type="radio"]) { + tr > *:has(.control-item-indicator[type="checkbox"]:not([role="switch"]), .control-item-indicator[type="radio"]) { width: 1%; padding: 0; vertical-align: middle; @@ -91,8 +88,7 @@ } // Automatically highlight rows with checked checkboxes or radios - tbody tr:has(.control-item-indicator[type="checkbox"]:not([role="switch"]):checked), - tbody tr:has(.control-item-indicator[type="radio"]:checked) { + tbody tr:has(.control-item-indicator[type="checkbox"]:not([role="switch"]):checked, .control-item-indicator[type="radio"]:checked) { @extend %active; }