From 4f31265927ea5f6f7f86364880323ddc834c5265 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Malfait?= Date: Tue, 28 Jul 2026 16:49:12 +0200 Subject: [PATCH] Fix 1px gap above the record table header (#23441) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem A transparent 1px slit shows up between the view bar and the table header row, letting the scrolled records show through above the column names. The record table header is `position: sticky; top: 0` inside the table's scroll container. On fractional device pixel ratios (scaled displays, browser zoom) the compositor can land the sticky header half a device pixel below the top edge of the scroll container, so its topmost device pixel row is painted with the scrolled content behind it instead of the header background. ## Repro Reproduced locally on `/objects/companies` with `deviceScaleFactor` 1.25, 1.75 and 2.25 — the slit appears at specific vertical scroll offsets (e.g. `scrollTop` 47 at DPR 1.75), and never at integer ratios. Before (DPR 1.75, `scrollTop` 47) — the row underneath bleeds through above "Name": before ## Fix Extend the header background 1px upwards with a `box-shadow` on the sticky container, so whatever half-pixel the compositor exposes is always covered. The shadow is painted as part of the sticky layer, so it follows the header wherever it lands. Nothing changes visually otherwise: when the table is scrolled to the top the shadow sits above the scroll container's padding box and is clipped away. ## Verification Scripted pixel scan of the top device-pixel row of the header, over scroll offsets 1-60 at DPR 1.25 / 1.5 / 1.75 / 2.25 / 2.5: | | before | after | |---|---|---| | DPR 1.25 | 3 offsets with a visible slit | 0 | | DPR 1.5 | 0 | 0 | | DPR 1.75 | 2 | 0 | | DPR 2.25 | 3 | 0 | | DPR 2.5 | 0 | 0 | Also checked at rest (`scrollTop` 0) and while scrolled at DPR 1 and 2 that no extra line appears above the header. `oxlint`, `oxfmt` and `nx typecheck twenty-front` pass. --- _Generated by [Claude Code](https://claude.ai/code/session_014gaDhmeDSNjdBeRRepKPAr)_ Review in cubic --- .../record-table-header/components/RecordTableHeader.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeader.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeader.tsx index 98e8f6b0d1..1f61139d1d 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeader.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeader.tsx @@ -8,8 +8,11 @@ import { isRecordTableCheckboxColumnHiddenComponentState } from '@/object-record import { isRecordTableDragColumnHiddenComponentState } from '@/object-record/record-table/states/isRecordTableDragColumnHiddenComponentState'; import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; import { styled } from '@linaria/react'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledHeaderContainer = styled.div` + background-color: ${themeCssVariables.background.primary}; + box-shadow: 0 -1px 0 ${themeCssVariables.background.primary}; display: flex; flex-direction: row; position: sticky;