Skip to content

Commit 3138c6a

Browse files
authored
fix: align DataTable checkbox vertically with row content (#320)
1 parent 5d7d7d3 commit 3138c6a

4 files changed

Lines changed: 49 additions & 48 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@tailor-platform/app-shell": patch
3+
---
4+
5+
Fix DataTable checkbox vertical alignment. Remove unnecessary wrapper div and `translate-y-[2px]` hack so checkboxes align correctly with row content via `align-middle`.
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
22

3-
exports[`Table > snapshots > basic table with header and body 1`] = `"<div data-slot="table-container" class="astw:relative astw:w-full astw:overflow-x-auto"><table data-slot="table" class="astw:w-full astw:caption-bottom astw:text-sm"><thead data-slot="table-header" class="astw:[&amp;_tr]:border-b"><tr data-slot="table-row" class="astw:hover:bg-muted/50 astw:data-[state=selected]:bg-muted astw:border-b astw:transition-colors"><th data-slot="table-head" class="astw:text-foreground astw:h-10 astw:px-2 astw:first:pl-6 astw:last:pr-6 astw:text-left astw:align-middle astw:font-medium astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0 astw:[&amp;>[role=checkbox]]:translate-y-[2px]">Name</th><th data-slot="table-head" class="astw:text-foreground astw:h-10 astw:px-2 astw:first:pl-6 astw:last:pr-6 astw:text-left astw:align-middle astw:font-medium astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0 astw:[&amp;>[role=checkbox]]:translate-y-[2px]">Status</th></tr></thead><tbody data-slot="table-body" class="astw:[&amp;_tr:last-child]:border-0"><tr data-slot="table-row" class="astw:hover:bg-muted/50 astw:data-[state=selected]:bg-muted astw:border-b astw:transition-colors"><td data-slot="table-cell" class="astw:px-2 astw:py-2 astw:first:pl-6 astw:last:pr-6 astw:align-middle astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0 astw:[&amp;>[role=checkbox]]:translate-y-[2px]">Item 1</td><td data-slot="table-cell" class="astw:px-2 astw:py-2 astw:first:pl-6 astw:last:pr-6 astw:align-middle astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0 astw:[&amp;>[role=checkbox]]:translate-y-[2px]">Active</td></tr></tbody></table></div>"`;
3+
exports[`Table > snapshots > basic table with header and body 1`] = `"<div data-slot="table-container" class="astw:relative astw:w-full astw:overflow-x-auto"><table data-slot="table" class="astw:w-full astw:caption-bottom astw:text-sm"><thead data-slot="table-header" class="astw:[&amp;_tr]:border-b"><tr data-slot="table-row" class="astw:hover:bg-muted/50 astw:data-[state=selected]:bg-muted astw:border-b astw:transition-colors"><th data-slot="table-head" class="astw:text-foreground astw:h-10 astw:px-2 astw:first:pl-6 astw:last:pr-6 astw:text-left astw:align-middle astw:font-medium astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0">Name</th><th data-slot="table-head" class="astw:text-foreground astw:h-10 astw:px-2 astw:first:pl-6 astw:last:pr-6 astw:text-left astw:align-middle astw:font-medium astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0">Status</th></tr></thead><tbody data-slot="table-body" class="astw:[&amp;_tr:last-child]:border-0"><tr data-slot="table-row" class="astw:hover:bg-muted/50 astw:data-[state=selected]:bg-muted astw:border-b astw:transition-colors"><td data-slot="table-cell" class="astw:px-2 astw:py-2 astw:first:pl-6 astw:last:pr-6 astw:align-middle astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0">Item 1</td><td data-slot="table-cell" class="astw:px-2 astw:py-2 astw:first:pl-6 astw:last:pr-6 astw:align-middle astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0">Active</td></tr></tbody></table></div>"`;
44

5-
exports[`Table > snapshots > empty table 1`] = `"<div data-slot="table-container" class="astw:relative astw:w-full astw:overflow-x-auto"><table data-slot="table" class="astw:w-full astw:caption-bottom astw:text-sm"><thead data-slot="table-header" class="astw:[&amp;_tr]:border-b"><tr data-slot="table-row" class="astw:hover:bg-muted/50 astw:data-[state=selected]:bg-muted astw:border-b astw:transition-colors"><th data-slot="table-head" class="astw:text-foreground astw:h-10 astw:px-2 astw:first:pl-6 astw:last:pr-6 astw:text-left astw:align-middle astw:font-medium astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0 astw:[&amp;>[role=checkbox]]:translate-y-[2px]">Name</th><th data-slot="table-head" class="astw:text-foreground astw:h-10 astw:px-2 astw:first:pl-6 astw:last:pr-6 astw:text-left astw:align-middle astw:font-medium astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0 astw:[&amp;>[role=checkbox]]:translate-y-[2px]">Status</th></tr></thead><tbody data-slot="table-body" class="astw:[&amp;_tr:last-child]:border-0"></tbody></table></div>"`;
5+
exports[`Table > snapshots > empty table 1`] = `"<div data-slot="table-container" class="astw:relative astw:w-full astw:overflow-x-auto"><table data-slot="table" class="astw:w-full astw:caption-bottom astw:text-sm"><thead data-slot="table-header" class="astw:[&amp;_tr]:border-b"><tr data-slot="table-row" class="astw:hover:bg-muted/50 astw:data-[state=selected]:bg-muted astw:border-b astw:transition-colors"><th data-slot="table-head" class="astw:text-foreground astw:h-10 astw:px-2 astw:first:pl-6 astw:last:pr-6 astw:text-left astw:align-middle astw:font-medium astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0">Name</th><th data-slot="table-head" class="astw:text-foreground astw:h-10 astw:px-2 astw:first:pl-6 astw:last:pr-6 astw:text-left astw:align-middle astw:font-medium astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0">Status</th></tr></thead><tbody data-slot="table-body" class="astw:[&amp;_tr:last-child]:border-0"></tbody></table></div>"`;
66

7-
exports[`Table > snapshots > table with caption 1`] = `"<div data-slot="table-container" class="astw:relative astw:w-full astw:overflow-x-auto"><table data-slot="table" class="astw:w-full astw:caption-bottom astw:text-sm"><caption data-slot="table-caption" class="astw:text-muted-foreground astw:mt-4 astw:text-sm">A list of items</caption><thead data-slot="table-header" class="astw:[&amp;_tr]:border-b"><tr data-slot="table-row" class="astw:hover:bg-muted/50 astw:data-[state=selected]:bg-muted astw:border-b astw:transition-colors"><th data-slot="table-head" class="astw:text-foreground astw:h-10 astw:px-2 astw:first:pl-6 astw:last:pr-6 astw:text-left astw:align-middle astw:font-medium astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0 astw:[&amp;>[role=checkbox]]:translate-y-[2px]">Name</th></tr></thead><tbody data-slot="table-body" class="astw:[&amp;_tr:last-child]:border-0"><tr data-slot="table-row" class="astw:hover:bg-muted/50 astw:data-[state=selected]:bg-muted astw:border-b astw:transition-colors"><td data-slot="table-cell" class="astw:px-2 astw:py-2 astw:first:pl-6 astw:last:pr-6 astw:align-middle astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0 astw:[&amp;>[role=checkbox]]:translate-y-[2px]">Item</td></tr></tbody></table></div>"`;
7+
exports[`Table > snapshots > table with caption 1`] = `"<div data-slot="table-container" class="astw:relative astw:w-full astw:overflow-x-auto"><table data-slot="table" class="astw:w-full astw:caption-bottom astw:text-sm"><caption data-slot="table-caption" class="astw:text-muted-foreground astw:mt-4 astw:text-sm">A list of items</caption><thead data-slot="table-header" class="astw:[&amp;_tr]:border-b"><tr data-slot="table-row" class="astw:hover:bg-muted/50 astw:data-[state=selected]:bg-muted astw:border-b astw:transition-colors"><th data-slot="table-head" class="astw:text-foreground astw:h-10 astw:px-2 astw:first:pl-6 astw:last:pr-6 astw:text-left astw:align-middle astw:font-medium astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0">Name</th></tr></thead><tbody data-slot="table-body" class="astw:[&amp;_tr:last-child]:border-0"><tr data-slot="table-row" class="astw:hover:bg-muted/50 astw:data-[state=selected]:bg-muted astw:border-b astw:transition-colors"><td data-slot="table-cell" class="astw:px-2 astw:py-2 astw:first:pl-6 astw:last:pr-6 astw:align-middle astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0">Item</td></tr></tbody></table></div>"`;
88

9-
exports[`Table > snapshots > table with containerClassName 1`] = `"<div data-slot="table-container" class="astw:relative astw:w-full astw:overflow-x-auto custom-container"><table data-slot="table" class="astw:w-full astw:caption-bottom astw:text-sm"><thead data-slot="table-header" class="astw:[&amp;_tr]:border-b"><tr data-slot="table-row" class="astw:hover:bg-muted/50 astw:data-[state=selected]:bg-muted astw:border-b astw:transition-colors"><th data-slot="table-head" class="astw:text-foreground astw:h-10 astw:px-2 astw:first:pl-6 astw:last:pr-6 astw:text-left astw:align-middle astw:font-medium astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0 astw:[&amp;>[role=checkbox]]:translate-y-[2px]">Name</th></tr></thead><tbody data-slot="table-body" class="astw:[&amp;_tr:last-child]:border-0"><tr data-slot="table-row" class="astw:hover:bg-muted/50 astw:data-[state=selected]:bg-muted astw:border-b astw:transition-colors"><td data-slot="table-cell" class="astw:px-2 astw:py-2 astw:first:pl-6 astw:last:pr-6 astw:align-middle astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0 astw:[&amp;>[role=checkbox]]:translate-y-[2px]">Item</td></tr></tbody></table></div>"`;
9+
exports[`Table > snapshots > table with containerClassName 1`] = `"<div data-slot="table-container" class="astw:relative astw:w-full astw:overflow-x-auto custom-container"><table data-slot="table" class="astw:w-full astw:caption-bottom astw:text-sm"><thead data-slot="table-header" class="astw:[&amp;_tr]:border-b"><tr data-slot="table-row" class="astw:hover:bg-muted/50 astw:data-[state=selected]:bg-muted astw:border-b astw:transition-colors"><th data-slot="table-head" class="astw:text-foreground astw:h-10 astw:px-2 astw:first:pl-6 astw:last:pr-6 astw:text-left astw:align-middle astw:font-medium astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0">Name</th></tr></thead><tbody data-slot="table-body" class="astw:[&amp;_tr:last-child]:border-0"><tr data-slot="table-row" class="astw:hover:bg-muted/50 astw:data-[state=selected]:bg-muted astw:border-b astw:transition-colors"><td data-slot="table-cell" class="astw:px-2 astw:py-2 astw:first:pl-6 astw:last:pr-6 astw:align-middle astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0">Item</td></tr></tbody></table></div>"`;
1010

11-
exports[`Table > snapshots > table with footer 1`] = `"<div data-slot="table-container" class="astw:relative astw:w-full astw:overflow-x-auto"><table data-slot="table" class="astw:w-full astw:caption-bottom astw:text-sm"><thead data-slot="table-header" class="astw:[&amp;_tr]:border-b"><tr data-slot="table-row" class="astw:hover:bg-muted/50 astw:data-[state=selected]:bg-muted astw:border-b astw:transition-colors"><th data-slot="table-head" class="astw:text-foreground astw:h-10 astw:px-2 astw:first:pl-6 astw:last:pr-6 astw:text-left astw:align-middle astw:font-medium astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0 astw:[&amp;>[role=checkbox]]:translate-y-[2px]">Product</th><th data-slot="table-head" class="astw:text-foreground astw:h-10 astw:px-2 astw:first:pl-6 astw:last:pr-6 astw:text-left astw:align-middle astw:font-medium astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0 astw:[&amp;>[role=checkbox]]:translate-y-[2px]">Price</th></tr></thead><tbody data-slot="table-body" class="astw:[&amp;_tr:last-child]:border-0"><tr data-slot="table-row" class="astw:hover:bg-muted/50 astw:data-[state=selected]:bg-muted astw:border-b astw:transition-colors"><td data-slot="table-cell" class="astw:px-2 astw:py-2 astw:first:pl-6 astw:last:pr-6 astw:align-middle astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0 astw:[&amp;>[role=checkbox]]:translate-y-[2px]">Widget</td><td data-slot="table-cell" class="astw:px-2 astw:py-2 astw:first:pl-6 astw:last:pr-6 astw:align-middle astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0 astw:[&amp;>[role=checkbox]]:translate-y-[2px]">$10</td></tr></tbody><tfoot data-slot="table-footer" class="astw:border-t astw:font-medium astw:[&amp;>tr]:last:border-b-0"><tr data-slot="table-row" class="astw:hover:bg-muted/50 astw:data-[state=selected]:bg-muted astw:border-b astw:transition-colors"><td data-slot="table-cell" class="astw:px-2 astw:py-2 astw:first:pl-6 astw:last:pr-6 astw:align-middle astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0 astw:[&amp;>[role=checkbox]]:translate-y-[2px]">Total</td><td data-slot="table-cell" class="astw:px-2 astw:py-2 astw:first:pl-6 astw:last:pr-6 astw:align-middle astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0 astw:[&amp;>[role=checkbox]]:translate-y-[2px]">$10</td></tr></tfoot></table></div>"`;
11+
exports[`Table > snapshots > table with footer 1`] = `"<div data-slot="table-container" class="astw:relative astw:w-full astw:overflow-x-auto"><table data-slot="table" class="astw:w-full astw:caption-bottom astw:text-sm"><thead data-slot="table-header" class="astw:[&amp;_tr]:border-b"><tr data-slot="table-row" class="astw:hover:bg-muted/50 astw:data-[state=selected]:bg-muted astw:border-b astw:transition-colors"><th data-slot="table-head" class="astw:text-foreground astw:h-10 astw:px-2 astw:first:pl-6 astw:last:pr-6 astw:text-left astw:align-middle astw:font-medium astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0">Product</th><th data-slot="table-head" class="astw:text-foreground astw:h-10 astw:px-2 astw:first:pl-6 astw:last:pr-6 astw:text-left astw:align-middle astw:font-medium astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0">Price</th></tr></thead><tbody data-slot="table-body" class="astw:[&amp;_tr:last-child]:border-0"><tr data-slot="table-row" class="astw:hover:bg-muted/50 astw:data-[state=selected]:bg-muted astw:border-b astw:transition-colors"><td data-slot="table-cell" class="astw:px-2 astw:py-2 astw:first:pl-6 astw:last:pr-6 astw:align-middle astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0">Widget</td><td data-slot="table-cell" class="astw:px-2 astw:py-2 astw:first:pl-6 astw:last:pr-6 astw:align-middle astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0">$10</td></tr></tbody><tfoot data-slot="table-footer" class="astw:border-t astw:font-medium astw:[&amp;>tr]:last:border-b-0"><tr data-slot="table-row" class="astw:hover:bg-muted/50 astw:data-[state=selected]:bg-muted astw:border-b astw:transition-colors"><td data-slot="table-cell" class="astw:px-2 astw:py-2 astw:first:pl-6 astw:last:pr-6 astw:align-middle astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0">Total</td><td data-slot="table-cell" class="astw:px-2 astw:py-2 astw:first:pl-6 astw:last:pr-6 astw:align-middle astw:whitespace-nowrap astw:[&amp;:has([role=checkbox])]:pr-0">$10</td></tr></tfoot></table></div>"`;

packages/core/src/components/data-table/data-table.tsx

Lines changed: 37 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -226,33 +226,31 @@ function DataTableHeaders({ className }: { className?: string }) {
226226
<Table.Row>
227227
{hasSelection && (
228228
<Table.Head style={{ width: 52 }} className="astw:pl-3!">
229-
<div className="astw:flex astw:items-center">
230-
<Checkbox.Root
231-
checked={isAllSelected}
232-
indeterminate={isIndeterminate}
233-
onCheckedChange={(checked) => {
234-
if (checked) {
235-
selectAllRows?.();
236-
} else {
237-
clearSelection?.();
238-
}
239-
}}
240-
aria-label={t("selectAll")}
241-
className={cn(
242-
"astw:flex astw:size-4 astw:items-center astw:justify-center astw:rounded-xs astw:border astw:border-input",
243-
"astw:data-checked:bg-primary astw:data-checked:border-primary astw:data-checked:text-primary-foreground",
244-
"astw:data-indeterminate:bg-primary astw:data-indeterminate:border-primary astw:data-indeterminate:text-primary-foreground",
229+
<Checkbox.Root
230+
checked={isAllSelected}
231+
indeterminate={isIndeterminate}
232+
onCheckedChange={(checked) => {
233+
if (checked) {
234+
selectAllRows?.();
235+
} else {
236+
clearSelection?.();
237+
}
238+
}}
239+
aria-label={t("selectAll")}
240+
className={cn(
241+
"astw:flex astw:size-4 astw:items-center astw:justify-center astw:rounded-xs astw:border astw:border-input",
242+
"astw:data-checked:bg-primary astw:data-checked:border-primary astw:data-checked:text-primary-foreground",
243+
"astw:data-indeterminate:bg-primary astw:data-indeterminate:border-primary astw:data-indeterminate:text-primary-foreground",
244+
)}
245+
>
246+
<Checkbox.Indicator className="astw:flex astw:data-unchecked:hidden">
247+
{isIndeterminate ? (
248+
<Minus className="astw:size-3" />
249+
) : (
250+
<Check className="astw:size-3" />
245251
)}
246-
>
247-
<Checkbox.Indicator className="astw:flex astw:data-unchecked:hidden">
248-
{isIndeterminate ? (
249-
<Minus className="astw:size-3" />
250-
) : (
251-
<Check className="astw:size-3" />
252-
)}
253-
</Checkbox.Indicator>
254-
</Checkbox.Root>
255-
</div>
252+
</Checkbox.Indicator>
253+
</Checkbox.Root>
256254
</Table.Head>
257255
)}
258256
{columns?.map((col, colIndex) => {
@@ -401,21 +399,19 @@ function DataTableBody({ className }: { className?: string }) {
401399
className="astw:pl-3!"
402400
onClick={(e) => e.stopPropagation()}
403401
>
404-
<div className="astw:flex astw:items-center">
405-
<Checkbox.Root
406-
checked={selected}
407-
onCheckedChange={() => toggleRowSelection(row)}
408-
aria-label={t("selectRow")}
409-
className={cn(
410-
"astw:flex astw:size-4 astw:items-center astw:justify-center astw:rounded-xs astw:border astw:border-input",
411-
"astw:data-checked:bg-primary astw:data-checked:border-primary astw:data-checked:text-primary-foreground",
412-
)}
413-
>
414-
<Checkbox.Indicator className="astw:flex astw:data-unchecked:hidden">
415-
<Check className="astw:size-3" />
416-
</Checkbox.Indicator>
417-
</Checkbox.Root>
418-
</div>
402+
<Checkbox.Root
403+
checked={selected}
404+
onCheckedChange={() => toggleRowSelection(row)}
405+
aria-label={t("selectRow")}
406+
className={cn(
407+
"astw:flex astw:size-4 astw:items-center astw:justify-center astw:rounded-xs astw:border astw:border-input",
408+
"astw:data-checked:bg-primary astw:data-checked:border-primary astw:data-checked:text-primary-foreground",
409+
)}
410+
>
411+
<Checkbox.Indicator className="astw:flex astw:data-unchecked:hidden">
412+
<Check className="astw:size-3" />
413+
</Checkbox.Indicator>
414+
</Checkbox.Root>
419415
</Table.Cell>
420416
)}
421417
{columns?.map((col, colIndex) => {

0 commit comments

Comments
 (0)