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
6 changes: 6 additions & 0 deletions .changeset/lucky-wasps-nail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@primer/react": major
"@primer/styled-react": patch
---

Remove support for `sx` from the `TabNav` component
21 changes: 9 additions & 12 deletions packages/react/src/TabNav/TabNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,14 @@ import {clsx} from 'clsx'
import type {To} from 'history'
import React, {useRef, useState} from 'react'
import {FocusKeys, useFocusZone} from '../hooks/useFocusZone'
import type {SxProp} from '../sx'
import type {ComponentProps} from '../utils/types'
import type {ForwardRefComponent as PolymorphicForwardRefComponent} from '../utils/polymorphic'

import styles from './TabNav.module.css'
import {BoxWithFallback} from '../internal/components/BoxWithFallback'

/**
* @deprecated
*/
export type TabNavProps = ComponentProps<typeof BoxWithFallback>
export type TabNavProps = React.HTMLProps<HTMLDivElement>

/**
* @deprecated
Expand Down Expand Up @@ -53,13 +51,13 @@ function TabNav({children, 'aria-label': ariaLabel, ...rest}: TabNavProps) {
)

return (
<BoxWithFallback {...rest} ref={navRef as React.RefObject<HTMLDivElement>}>
<div {...rest} ref={navRef as React.RefObject<HTMLDivElement>}>
<nav aria-label={ariaLabel} className={styles.TabNavNav}>
<div role="tablist" className={styles.TabNavTabList}>
{children}
</div>
</nav>
</BoxWithFallback>
</div>
)
}

Expand All @@ -73,18 +71,17 @@ export type TabNavLinkProps = React.DetailedHTMLProps<React.HTMLAttributes<HTMLA
className?: string
as?: React.ElementType | 'a' | 'button' | 'div'
disabled?: boolean
} & SxProp
}

/**
* @deprecated
*/
const TabNavLink = React.forwardRef<HTMLAnchorElement, TabNavLinkProps>(function TabNavLink(
{selected, className, as = 'a', ...rest}: TabNavLinkProps,
const TabNavLink = React.forwardRef(function TabNavLink(
{selected, className, as: Component = 'a', ...rest}: TabNavLinkProps,
ref,
) {
return (
<BoxWithFallback
as={as}
<Component
ref={ref}
role="tab"
tabIndex={-1}
Expand All @@ -93,7 +90,7 @@ const TabNavLink = React.forwardRef<HTMLAnchorElement, TabNavLinkProps>(function
{...rest}
/>
)
})
}) as PolymorphicForwardRefComponent<'a', TabNavLinkProps>

TabNavLink.displayName = 'TabNav.Link'

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {render, screen} from '@testing-library/react'
import {describe, expect, test} from 'vitest'
import {Dialog, Octicon, TabNav, Tooltip} from '../deprecated'
import {Button} from '../index'

describe('@primer/react/deprecated', () => {
test('Dialog supports `sx` prop', () => {
Expand All @@ -19,8 +20,10 @@ describe('@primer/react/deprecated', () => {
})

test('TabNav.Link supports `sx` prop', () => {
render(<TabNav.Link data-testid="component" sx={{background: 'red'}} />)
render(<TabNav.Link data-testid="component" sx={{background: 'red'}} as={Button} />)
expect(window.getComputedStyle(screen.getByTestId('component')).backgroundColor).toBe('rgb(255, 0, 0)')
expect(window.getComputedStyle(screen.getByRole('tab')).backgroundColor).toBe('rgb(255, 0, 0)')
expect(screen.getByRole('tab').tagName).toBe('BUTTON')
})

test('Tooltip supports `sx` prop', () => {
Expand Down
32 changes: 32 additions & 0 deletions packages/styled-react/src/components/TabNav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import {TabNav as PrimerTabNav} from '@primer/react/deprecated'
import type {TabNavProps as PrimerTabNavProps, TabNavLinkProps as PrimerTabNavLinkProps} from '@primer/react/deprecated'
import {sx, type SxProp} from '../sx'
import styled from 'styled-components'
import {type ForwardRefComponent} from '../polymorphic'

type TabNavProps = PrimerTabNavProps & SxProp
type TabNavLinkProps = PrimerTabNavLinkProps & SxProp

const StyledTabNav = styled(PrimerTabNav).withConfig({
shouldForwardProp: prop => (prop as keyof TabNavProps) !== 'sx',
})<TabNavProps>`
${sx}
`

// @ts-ignore forwardedAs is valid here but I don't know how to fix the typescript error
const TabNavImpl = ({as, ...props}: TabNavProps) => <StyledTabNav forwardedAs={as} {...props} />
Comment on lines +16 to +17
Copy link
Preview

Copilot AI Sep 25, 2025

Choose a reason for hiding this comment

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

Instead of using @ts-ignore, consider using a proper TypeScript assertion or interface extension to handle the forwardedAs prop. This improves type safety and code maintainability.

Copilot uses AI. Check for mistakes.


const StyledTabNavLink: ForwardRefComponent<'a', TabNavLinkProps> = styled(PrimerTabNav.Link).withConfig({
shouldForwardProp: prop => (prop as keyof TabNavLinkProps) !== 'sx',
})<TabNavLinkProps>`
${sx}
`

// @ts-ignore forwardedAs is valid here but I don't know how to fix the typescript error
const TabNavLink = ({as, ...props}: TabNavLinkProps) => <StyledTabNavLink forwardedAs={as} {...props} />
Comment on lines +25 to +26
Copy link
Preview

Copilot AI Sep 25, 2025

Choose a reason for hiding this comment

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

Instead of using @ts-ignore, consider using a proper TypeScript assertion or interface extension to handle the forwardedAs prop. This improves type safety and code maintainability.

Copilot uses AI. Check for mistakes.


const TabNav = Object.assign(TabNavImpl, {
Link: TabNavLink,
})

export {TabNav, type TabNavProps, type TabNavLinkProps}
3 changes: 2 additions & 1 deletion packages/styled-react/src/deprecated.tsx
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export {Dialog, Octicon, TabNav, Tooltip, type TooltipProps} from '@primer/react/deprecated'
export {TabNav, type TabNavProps, type TabNavLinkProps} from './components/TabNav'
export {Dialog, Octicon, Tooltip, type TooltipProps} from '@primer/react/deprecated'
Loading