From 7eb9d13347134d5199258f92d3f98a3b97e14401 Mon Sep 17 00:00:00 2001 From: Max Kainov Date: Thu, 5 Mar 2026 22:25:17 +0100 Subject: [PATCH 1/2] feat(Table): add disableMobileListView prop to prevent mobile list conversion Add new prop to Table component that disables the automatic conversion to mobile list view on narrow screens, keeping the table layout with horizontal scroll instead. Changes: - Add disableMobileListView?: boolean prop (default: false) - Set data-responsive-mode attribute on TableOuterContainer - Wrap all mobile @media queries with [data-responsive-mode="list"] & selector - When disableMobileListView=true, mobile styles don't apply Benefits: - Simple implementation (3 main changes) - No prop threading through nested components - Clean CSS selector approach - Backward compatible (default behavior unchanged) Use case: When you want tables to scroll horizontally on mobile instead of converting to a list view format. --- src/components/Table/Table.tsx | 169 +++++++++++++++++++-------------- 1 file changed, 98 insertions(+), 71 deletions(-) diff --git a/src/components/Table/Table.tsx b/src/components/Table/Table.tsx index f9784eaa9..a1782e892 100644 --- a/src/components/Table/Table.tsx +++ b/src/components/Table/Table.tsx @@ -315,26 +315,28 @@ const TableRow = styled.tr` border-bottom: none; } - @media (max-width: 768px) { - position: relative; - display: flex; - flex-wrap: wrap; - ${({ theme, $isSelectable = false, $showActions = false }) => ` - border: ${theme.click.table.cell.stroke} solid ${ - theme.click.table.row.color.stroke.default - }; - border-radius: ${theme.click.table.radii.all}; - ${ - $isSelectable - ? `padding-left: calc(${theme.click.table.body.cell.space.sm.x} + ${theme.click.table.body.cell.space.sm.x} + ${theme.click.checkbox.size.all});` - : '' - } - ${ - $showActions - ? `padding-right: calc(${theme.click.table.body.cell.space.sm.x} + ${theme.click.table.body.cell.space.sm.x} + ${theme.click.image.sm.size.width} + ${theme.click.button.iconButton.default.space.x} + ${theme.click.button.iconButton.default.space.x});` - : '' - } - `} + [data-responsive-mode='list'] & { + @media (max-width: 768px) { + position: relative; + display: flex; + flex-wrap: wrap; + ${({ theme, $isSelectable = false, $showActions = false }) => ` + border: ${theme.click.table.cell.stroke} solid ${ + theme.click.table.row.color.stroke.default + }; + border-radius: ${theme.click.table.radii.all}; + ${ + $isSelectable + ? `padding-left: calc(${theme.click.table.body.cell.space.sm.x} + ${theme.click.table.body.cell.space.sm.x} + ${theme.click.checkbox.size.all});` + : '' + } + ${ + $showActions + ? `padding-right: calc(${theme.click.table.body.cell.space.sm.x} + ${theme.click.table.body.cell.space.sm.x} + ${theme.click.image.sm.size.width} + ${theme.click.button.iconButton.default.space.x} + ${theme.click.button.iconButton.default.space.x});` + : '' + } + `} + } } `; @@ -345,18 +347,22 @@ const TableData = styled.td<{ $size: TableSize }>` font: ${theme.click.table.cell.text.default}; padding: ${theme.click.table.body.cell.space[$size].y} ${theme.click.table.body.cell.space[$size].x}; `} - @media (max-width: 768px) { - width: auto; - min-width: 40%; - ${({ theme }) => ` - padding: ${theme.click.table.body.cell.space.sm.y} ${theme.click.table.body.cell.space.sm.x}; - `} + [data-responsive-mode="list"] & { + @media (max-width: 768px) { + width: auto; + min-width: 40%; + ${({ theme }) => ` + padding: ${theme.click.table.body.cell.space.sm.y} ${theme.click.table.body.cell.space.sm.x}; + `} + } } `; const StyledColGroup = styled.colgroup` - @media (max-width: 768px) { - display: none; + [data-responsive-mode='list'] & { + @media (max-width: 768px) { + display: none; + } } `; const StyledThead = styled.thead` @@ -368,8 +374,10 @@ const StyledThead = styled.thead` }) => ` border-bottom: ${theme.click.table.cell.stroke} solid ${theme.click.table.row.color.stroke.default}; `} } - @media (max-width: 768px) { - display: none; + [data-responsive-mode='list'] & { + @media (max-width: 768px) { + display: none; + } } `; @@ -379,15 +387,19 @@ const MobileHeader = styled.div` color: ${theme.click.table.row.color.label.default}; font: ${theme.click.table.cell.label.default}; `} - @media (max-width: 768px) { - display: block; + [data-responsive-mode="list"] & { + @media (max-width: 768px) { + display: block; + } } `; const Tbody = styled.tbody` - @media (max-width: 768px) { - display: flex; - flex-direction: column; - gap: 0.25rem; + [data-responsive-mode='list'] & { + @media (max-width: 768px) { + display: flex; + flex-direction: column; + gap: 0.25rem; + } } `; @@ -398,17 +410,19 @@ const SelectData = styled.td<{ $size: TableSize }>` font: ${theme.click.table.cell.text.default}; padding: ${theme.click.table.body.cell.space[$size].y} ${theme.click.table.body.cell.space[$size].x}; `} - @media (max-width: 768px) { - width: auto; - align-self: stretch; - position: absolute; - left: 0; - top: 0; - bottom: 0; - ${({ theme }) => ` - padding: ${theme.click.table.body.cell.space.sm.y} ${theme.click.table.body.cell.space.sm.x}; - border-right: ${theme.click.table.cell.stroke} solid ${theme.click.table.row.color.stroke.default}; - `} + [data-responsive-mode="list"] & { + @media (max-width: 768px) { + width: auto; + align-self: stretch; + position: absolute; + left: 0; + top: 0; + bottom: 0; + ${({ theme }) => ` + padding: ${theme.click.table.body.cell.space.sm.y} ${theme.click.table.body.cell.space.sm.x}; + border-right: ${theme.click.table.cell.stroke} solid ${theme.click.table.row.color.stroke.default}; + `} + } } `; const ActionsList = styled.td<{ $size: TableSize }>` @@ -418,17 +432,19 @@ const ActionsList = styled.td<{ $size: TableSize }>` font: ${theme.click.table.cell.text.default}; padding: ${theme.click.table.body.cell.space[$size].y} ${theme.click.table.body.cell.space[$size].x}; `} - @media (max-width: 768px) { - width: auto; - align-self: stretch; - position: absolute; - right: 0; - top: 0; - bottom: 0; - ${({ theme }) => ` - padding: ${theme.click.table.body.cell.space.sm.y} ${theme.click.table.body.cell.space.sm.x}; - border-left: 1px solid ${theme.click.table.row.color.stroke.default}; - `} + [data-responsive-mode="list"] & { + @media (max-width: 768px) { + width: auto; + align-self: stretch; + position: absolute; + right: 0; + top: 0; + bottom: 0; + ${({ theme }) => ` + padding: ${theme.click.table.body.cell.space.sm.y} ${theme.click.table.body.cell.space.sm.x}; + border-left: 1px solid ${theme.click.table.row.color.stroke.default}; + `} + } } `; @@ -437,10 +453,12 @@ const ActionsContainer = styled.div` flex-wrap: wrap; gap: 0.5rem; overflow: hidden; - @media (max-width: 768px) { - flex-direction: column; - overflow: auto; - flex-wrap: nowrap; + [data-responsive-mode='list'] & { + @media (max-width: 768px) { + flex-direction: column; + overflow: auto; + flex-wrap: nowrap; + } } `; @@ -463,11 +481,13 @@ const TableOuterContainer = styled.div` const MobileActions = styled.div` display: none; - @media (max-width: 768px) { - display: flex; - justify-content: space-between; - align-items: center; - padding: 0 ${({ theme }) => theme.click.table.body.cell.space.sm.x}; + [data-responsive-mode='list'] & { + @media (max-width: 768px) { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 ${({ theme }) => theme.click.table.body.cell.space.sm.x}; + } } `; const EditButton = styled.button` @@ -523,6 +543,8 @@ interface CommonTableProps extends Omit< showHeader?: boolean; rowHeight?: string; resizableColumns?: boolean; + /** Disables mobile list view on narrow screens. When true, table uses horizontal scroll instead. Default: false */ + disableMobileListView?: boolean; } type SelectReturnValue = { @@ -711,6 +733,7 @@ const Table = forwardRef( showHeader = true, rowHeight, resizableColumns, + disableMobileListView = false, ...props }, ref @@ -867,7 +890,9 @@ const Table = forwardRef( } return ( - + {hasRows && showHeader && ( {isSelectable && ( @@ -1060,9 +1085,11 @@ const StyledTable = styled.table` overflow: hidden; table-layout: fixed; - @media (max-width: 768px) { - border: none; - table-layout: auto; + [data-responsive-mode='list'] & { + @media (max-width: 768px) { + border: none; + table-layout: auto; + } } `; From 8a93b54fa0a7495758b9b9592c9a248ea526f4fe Mon Sep 17 00:00:00 2001 From: Max Kainov Date: Fri, 6 Mar 2026 15:51:42 +0100 Subject: [PATCH 2/2] Use theme breakpoint instead of hardcoded 768px --- src/components/Table/Table.tsx | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/components/Table/Table.tsx b/src/components/Table/Table.tsx index 7cc1731a0..03dbae023 100644 --- a/src/components/Table/Table.tsx +++ b/src/components/Table/Table.tsx @@ -352,7 +352,7 @@ const TableRow = styled.tr` } [data-responsive-mode='list'] & { - @media (max-width: 768px) { + @media (max-width: ${({ theme }) => theme.breakpoint.sizes.md}) { position: relative; display: flex; flex-wrap: wrap; @@ -384,7 +384,7 @@ const TableData = styled.td<{ $size: TableSize }>` padding: ${theme.click.table.body.cell.space[$size].y} ${theme.click.table.body.cell.space[$size].x}; `} [data-responsive-mode="list"] & { - @media (max-width: 768px) { + @media (max-width: ${({ theme }) => theme.breakpoint.sizes.md}) { width: auto; min-width: 40%; ${({ theme }) => ` @@ -396,7 +396,7 @@ const TableData = styled.td<{ $size: TableSize }>` const StyledColGroup = styled.colgroup` [data-responsive-mode='list'] & { - @media (max-width: 768px) { + @media (max-width: ${({ theme }) => theme.breakpoint.sizes.md}) { display: none; } } @@ -411,7 +411,7 @@ const StyledThead = styled.thead` `} } [data-responsive-mode='list'] & { - @media (max-width: 768px) { + @media (max-width: ${({ theme }) => theme.breakpoint.sizes.md}) { display: none; } } @@ -424,14 +424,14 @@ const MobileHeader = styled.div` font: ${theme.click.table.cell.label.default}; `} [data-responsive-mode="list"] & { - @media (max-width: 768px) { + @media (max-width: ${({ theme }) => theme.breakpoint.sizes.md}) { display: block; } } `; const Tbody = styled.tbody` [data-responsive-mode='list'] & { - @media (max-width: 768px) { + @media (max-width: ${({ theme }) => theme.breakpoint.sizes.md}) { display: flex; flex-direction: column; gap: 0.25rem; @@ -447,7 +447,7 @@ const SelectData = styled.td<{ $size: TableSize }>` padding: ${theme.click.table.body.cell.space[$size].y} ${theme.click.table.body.cell.space[$size].x}; `} [data-responsive-mode="list"] & { - @media (max-width: 768px) { + @media (max-width: ${({ theme }) => theme.breakpoint.sizes.md}) { width: auto; align-self: stretch; position: absolute; @@ -469,7 +469,7 @@ const ActionsList = styled.td<{ $size: TableSize }>` padding: ${theme.click.table.body.cell.space[$size].y} ${theme.click.table.body.cell.space[$size].x}; `} [data-responsive-mode="list"] & { - @media (max-width: 768px) { + @media (max-width: ${({ theme }) => theme.breakpoint.sizes.md}) { width: auto; align-self: stretch; position: absolute; @@ -490,7 +490,7 @@ const ActionsContainer = styled.div` gap: 0.5rem; overflow: hidden; [data-responsive-mode='list'] & { - @media (max-width: 768px) { + @media (max-width: ${({ theme }) => theme.breakpoint.sizes.md}) { flex-direction: column; overflow: auto; flex-wrap: nowrap; @@ -518,7 +518,7 @@ const TableOuterContainer = styled.div` const MobileActions = styled.div` display: none; [data-responsive-mode='list'] & { - @media (max-width: 768px) { + @media (max-width: ${({ theme }) => theme.breakpoint.sizes.md}) { display: flex; justify-content: space-between; align-items: center; @@ -1163,7 +1163,7 @@ const StyledTable = styled.table` table-layout: fixed; [data-responsive-mode='list'] & { - @media (max-width: 768px) { + @media (max-width: ${({ theme }) => theme.breakpoint.sizes.md}) { border: none; table-layout: auto; }