From 9e35e89ac43fc8973fb20cffaadcb564cef1d433 Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Mon, 19 Jan 2026 13:25:28 +0100 Subject: [PATCH 1/3] add playwright mcp server --- .vscode/settings.json | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index c5f11daa02b..7629b1e8e4d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,12 @@ { + "mcp": { + "servers": { + "playwright": { + "command": "npx", + "args": ["@playwright/mcp@latest"] + } + } + }, "typescript.tsdk": "node_modules/typescript/lib", "editor.formatOnSave": true, "[javascript]": { @@ -17,10 +25,7 @@ "source.fixAll.stylelint": "explicit" } }, - "stylelint.validate": [ - "css", - "postcss" - ], + "stylelint.validate": ["css", "postcss"], "json.schemas": [ { "fileMatch": ["*.docs.json"], From 61ad00af311a063ab8a1e9580d2997e9ce710846 Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Wed, 21 Jan 2026 10:39:47 +0100 Subject: [PATCH 2/3] fixture --- examples/nextjs/next-env.d.ts | 2 +- examples/nextjs/src/app/underlinenav/page.tsx | 42 +++++++++++++++++++ package-lock.json | 8 ++-- packages/react/package.json | 1 + 4 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 examples/nextjs/src/app/underlinenav/page.tsx diff --git a/examples/nextjs/next-env.d.ts b/examples/nextjs/next-env.d.ts index c4e7c0ebef4..c4b7818fbb2 100644 --- a/examples/nextjs/next-env.d.ts +++ b/examples/nextjs/next-env.d.ts @@ -1,6 +1,6 @@ /// /// -import './.next/types/routes.d.ts' +import "./.next/dev/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/examples/nextjs/src/app/underlinenav/page.tsx b/examples/nextjs/src/app/underlinenav/page.tsx new file mode 100644 index 00000000000..b4d4f7cb1ef --- /dev/null +++ b/examples/nextjs/src/app/underlinenav/page.tsx @@ -0,0 +1,42 @@ +'use client' + +import React from 'react' +import {UnderlineNav} from '@primer/react' + +export default function UnderlineNavPage() { + const [selectedIndex, setSelectedIndex] = React.useState(1) + + const items: {navigation: string; counter?: number | string; href?: string}[] = [ + {navigation: 'Code', href: '#code'}, + {navigation: 'Issues', counter: '12K', href: '#issues'}, + {navigation: 'Pull Requests', counter: 13, href: '#pull-requests'}, + {navigation: 'Discussions', counter: 5, href: '#discussions'}, + {navigation: 'Actions', counter: 4, href: '#actions'}, + {navigation: 'Projects', counter: 9, href: '#projects'}, + {navigation: 'Insights', counter: '0', href: '#insights'}, + {navigation: 'Settings', counter: 10, href: '#settings'}, + {navigation: 'Security', href: '#security'}, + ] + + return ( +
+

UnderlineNav - Overflow on Narrow Screen

+ + {items.map((item, index) => ( + { + event.preventDefault() + setSelectedIndex(index) + }} + counter={item.counter} + href={item.href} + > + {item.navigation} + + ))} + +
+ ) +} diff --git a/package-lock.json b/package-lock.json index c08231f808a..0978b7100e9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -81,7 +81,7 @@ "react-dom": "^18.3.1" }, "devDependencies": { - "@primer/react": "38.7.0", + "@primer/react": "38.7.1", "@primer/styled-react": "1.0.2", "@types/react": "^18.3.11", "@types/react-dom": "^18.3.0", @@ -95,7 +95,7 @@ "name": "example-nextjs", "version": "0.0.0", "dependencies": { - "@primer/react": "38.7.0", + "@primer/react": "38.7.1", "@primer/styled-react": "1.0.2", "next": "^16.0.10", "react": "^19.2.0", @@ -138,7 +138,7 @@ "version": "0.0.0", "dependencies": { "@primer/octicons-react": "^19.21.0", - "@primer/react": "38.7.0", + "@primer/react": "38.7.1", "@primer/styled-react": "1.0.2", "clsx": "^2.1.1", "next": "^16.0.10", @@ -26428,7 +26428,7 @@ }, "packages/react": { "name": "@primer/react", - "version": "38.7.0", + "version": "38.7.1", "license": "MIT", "dependencies": { "@github/mini-throttle": "^2.1.1", diff --git a/packages/react/package.json b/packages/react/package.json index 3c5ca6990b2..2a0cac7455b 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -37,6 +37,7 @@ ], "scripts": { "build": "./script/build", + "build:components": "npx rollup -c", "clean": "rimraf dist generated", "start": "concurrently npm:start:*", "start:storybook": "STORYBOOK=true storybook dev -p 6006", From be5ec9e7c3d0fccc92ab10cee275fa1c30a06f59 Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Wed, 21 Jan 2026 14:23:05 +0100 Subject: [PATCH 3/3] add data-ssr-hidden attribute --- .../components/UnderlineTabbedInterface.module.css | 7 +++++++ .../internal/components/UnderlineTabbedInterface.tsx | 12 +++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/packages/react/src/internal/components/UnderlineTabbedInterface.module.css b/packages/react/src/internal/components/UnderlineTabbedInterface.module.css index 85214c5c317..5ef756cd49b 100644 --- a/packages/react/src/internal/components/UnderlineTabbedInterface.module.css +++ b/packages/react/src/internal/components/UnderlineTabbedInterface.module.css @@ -12,6 +12,13 @@ /* stylelint-disable-next-line primer/box-shadow */ box-shadow: inset 0 -1px var(--borderColor-muted); + /* Hide overflow during SSR to prevent horizontal scrollbar before JS hydration calculates which items fit */ + overflow: hidden; + + &[data-ssr-hidden='false'] { + overflow: visible; + } + &[data-variant='flush'] { /* stylelint-disable-next-line primer/spacing */ padding-inline: unset; diff --git a/packages/react/src/internal/components/UnderlineTabbedInterface.tsx b/packages/react/src/internal/components/UnderlineTabbedInterface.tsx index a6fa4bee785..b758d6cabff 100644 --- a/packages/react/src/internal/components/UnderlineTabbedInterface.tsx +++ b/packages/react/src/internal/components/UnderlineTabbedInterface.tsx @@ -1,11 +1,12 @@ // Used for UnderlineNav and UnderlinePanels components -import React from 'react' +import React, {useState} from 'react' import {type ForwardedRef, forwardRef, type FC, type PropsWithChildren, type ElementType} from 'react' import {isElement} from 'react-is' import type {IconProps} from '@primer/octicons-react' import CounterLabel from '../../CounterLabel' import type {ForwardRefComponent as PolymorphicForwardRefComponent} from '../../utils/polymorphic' +import useIsomorphicLayoutEffect from '../../utils/useIsomorphicLayoutEffect' import classes from './UnderlineTabbedInterface.module.css' import {clsx} from 'clsx' @@ -22,10 +23,19 @@ type UnderlineWrapperProps = { export const UnderlineWrapper = forwardRef((props, ref) => { const {children, className, as: Component = 'div', ...rest} = props + // Track hydration state: true on server and initial client render, false after hydration + const [isSSR, setIsSSR] = useState(true) + + useIsomorphicLayoutEffect(() => { + // After hydration, allow overflow to be visible + setIsSSR(false) + }, []) + return ( } + data-ssr-hidden={isSSR ? 'true' : 'false'} {...rest} > {children}