diff --git a/.changeset/perf-banner-has-selector.md b/.changeset/perf-banner-has-selector.md new file mode 100644 index 00000000000..d7ff0ac63e8 --- /dev/null +++ b/.changeset/perf-banner-has-selector.md @@ -0,0 +1,8 @@ +--- +'@primer/react': patch +--- + +perf(Banner): Optimize CSS :has() selectors for better INP + +- Scope `:has(.BannerActions)` selectors to shallow path `> * >` for O(1) lookup +- Scope `:has(.BannerActionsContainer)` to direct child with `>` combinator diff --git a/packages/react/src/Banner/Banner.module.css b/packages/react/src/Banner/Banner.module.css index 07b04346567..5377ecead6b 100644 --- a/packages/react/src/Banner/Banner.module.css +++ b/packages/react/src/Banner/Banner.module.css @@ -119,7 +119,8 @@ margin-block: var(--base-size-8); } -.Banner[data-title-hidden]:not(:has(.BannerActions)) .BannerContent { +/* PERFORMANCE: BannerActions is inside BannerContainer, use shallow path > * > for O(1) lookup */ +.Banner[data-title-hidden]:not(:has(> * > .BannerActions)) .BannerContent { margin-block: var(--base-size-6); } @@ -152,8 +153,9 @@ fill: var(--banner-icon-fgColor); } +/* PERFORMANCE: BannerActions is inside BannerContainer, use shallow path > * > for O(1) lookup */ /* stylelint-disable-next-line selector-max-specificity */ -.Banner[data-title-hidden]:not(:has(.BannerActions)) .BannerIcon svg { +.Banner[data-title-hidden]:not(:has(> * > .BannerActions)) .BannerIcon svg { height: var(--base-size-16); } @@ -166,7 +168,8 @@ margin-inline-start: var(--base-size-4); } -:where(.Banner):has(.BannerActions) .BannerDismiss { +/* PERFORMANCE: BannerActions is inside BannerContainer, use shallow path > * > for O(1) lookup */ +:where(.Banner):has(> * > .BannerActions) .BannerDismiss { margin-block: var(--base-size-2); } @@ -211,7 +214,8 @@ display: grid; } - .BannerContainer:has(.BannerActionsContainer) { + /* PERFORMANCE: BannerActionsContainer is direct child of BannerContainer, scope with > for O(1) lookup */ + .BannerContainer:has(> .BannerActionsContainer) { grid-template-rows: auto auto; }