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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/shiny-buckets-study.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@primer/react': patch
---

reapplies PageLayout resizable enhancements without INP drop from expensive selectors
2 changes: 2 additions & 0 deletions e2e/components/Axe.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ const SKIPPED_TESTS = [
'components-flash-features--with-icon-action-dismiss', // TODO: Remove once color-contrast issues have been resolved
'components-flash-features--with-icon-and-action', // TODO: Remove once color-contrast issues have been resolved
'components-filteredactionlist--default',
'components-pagelayout-performance-tests--medium-content',
'components-pagelayout-performance-tests--heavy-content',
]

type Component = {
Expand Down
84 changes: 74 additions & 10 deletions packages/react/src/PageLayout/PageLayout.module.css
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
/* Maintain resize cursor while dragging */
/* stylelint-disable-next-line selector-no-qualifying-type */
body[data-page-layout-dragging='true'] {
cursor: col-resize;
}

/* Disable text selection while dragging */
/* stylelint-disable-next-line selector-no-qualifying-type */
body[data-page-layout-dragging='true'] * {
user-select: none;
/* Exported values for JavaScript consumption */
:export {
/* Breakpoint where --pane-max-width-diff changes (used in usePaneWidth.ts) */
paneMaxWidthDiffBreakpoint: 1280;
/* Default value for --pane-max-width-diff below the breakpoint */
paneMaxWidthDiffDefault: 511;
}
Comment on lines +1 to 7
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure if we have prefernces for using these across JS/CSS or just duplicating them?

Copy link
Member

@siddharthkp siddharthkp Dec 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL about :export

Sorry, trying to understand the goal here. Why are these exported from PageLayout.module.css? We don't use them in this file

Nevermind, I realise you can't use the exports within the file because they will be removed during compilation


.PageLayoutRoot {
Expand All @@ -31,6 +27,7 @@ body[data-page-layout-dragging='true'] * {
--pane-width-small: 100%;
--pane-width-medium: 100%;
--pane-width-large: 100%;
/* NOTE: This value is exported via :export for use in usePaneWidth.ts */
--pane-max-width-diff: 511px;

@media screen and (min-width: 768px) {
Expand All @@ -45,6 +42,7 @@ body[data-page-layout-dragging='true'] * {
--pane-width-large: 320px;
}

/* NOTE: This breakpoint value is exported via :export for use in usePaneWidth.ts */
@media screen and (min-width: 1280px) {
--pane-max-width-diff: 959px;
}
Expand Down Expand Up @@ -383,6 +381,26 @@ body[data-page-layout-dragging='true'] * {
}
}

/**
* OPTIMIZATION: Aggressive containment during drag for ContentWrapper
* data-dragging is set on PageLayoutContent by JavaScript
* This avoids expensive :has() selectors
*/
.PageLayoutContent[data-dragging='true'] .ContentWrapper {
/* Add paint containment during drag - safe since user can't interact */
contain: layout style paint;

/* Disable interactions */
pointer-events: none;

/* Disable transitions to prevent expensive recalculations */
transition: none;

/* Force compositor layer for hardware acceleration */
will-change: width;
transform: translateZ(0);
}

.Content {
width: 100%;

Expand All @@ -409,6 +427,16 @@ body[data-page-layout-dragging='true'] * {
}
}

/**
* OPTIMIZATION: Freeze content layout during resize drag
* This prevents expensive recalculations of large content areas
* while keeping content visible (just frozen in place)
*/
.PageLayoutContent[data-dragging='true'] .Content {
/* Full containment (without size) - isolate from layout recalculations */
contain: layout style paint;
}

.PaneWrapper {
display: flex;
width: 100%;
Expand Down Expand Up @@ -593,11 +621,36 @@ body[data-page-layout-dragging='true'] * {
width: 100%;

@media screen and (min-width: 768px) {
/*
* --pane-max-width is set by JS on mount and updated on resize (debounced).
* JS calculates viewport - margin to avoid scrollbar discrepancy with 100vw.
*/
width: clamp(var(--pane-min-width), var(--pane-width), var(--pane-max-width));
}
}
}

/**
* OPTIMIZATION: Performance enhancements for Pane during drag
* data-dragging is set on PageLayoutContent by JavaScript
* This avoids expensive :has() selectors
*/
.PageLayoutContent[data-dragging='true'] .Pane {
/* Full containment - isolate from layout recalculations */
contain: layout style paint;

/* Disable interactions during drag */
pointer-events: none;

/* Disable transitions during drag */
transition: none;

/* Force hardware acceleration */
will-change: width, transform;
transform: translateZ(0);
backface-visibility: hidden;
}

.PaneHorizontalDivider {
&:where([data-position='start']) {
/* stylelint-disable-next-line primer/spacing */
Expand Down Expand Up @@ -696,12 +749,22 @@ body[data-page-layout-dragging='true'] * {
padding: var(--spacing);
}

/**
* DraggableHandle - Interactive resize handle
*/
.DraggableHandle {
position: absolute;
inset: 0 -2px;
cursor: col-resize;
background-color: transparent;
transition-delay: 0.1s;

/**
* OPTIMIZATION: Prevent touch scrolling and text selection during drag
* This is done in CSS because it needs to be set before any pointer events
*/
touch-action: none;
user-select: none;
}

.DraggableHandle:hover {
Expand All @@ -710,6 +773,7 @@ body[data-page-layout-dragging='true'] * {

.DraggableHandle[data-dragging='true'] {
background-color: var(--bgColor-accent-emphasis);
cursor: col-resize;
}

.DraggableHandle[data-dragging='true']:hover {
Expand Down
Loading
Loading