Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
dcae302
Expose `useMergedRefs` and make ready for React 19
iansan5653 Mar 17, 2026
bb26a62
Add unit tests for `useMergedRefs`
iansan5653 Mar 17, 2026
3d854c9
Update import paths
iansan5653 Mar 17, 2026
8e77831
Deprecate `useProvidedRefOrCreate` and `useRefObjectAsForwardedRef`
iansan5653 Mar 17, 2026
973f184
Add changeset
iansan5653 Mar 17, 2026
63fca28
Deprecate `useProvidedRefOrCreate` and migrate everything except for …
iansan5653 Mar 9, 2026
3b478e3
Migrate `AnchoredOverlay` anchor ref
iansan5653 Mar 9, 2026
04e1ca7
Drop more ts-expect-error!
iansan5653 Mar 9, 2026
ec31af7
Revert behaviors docs
iansan5653 Mar 9, 2026
7bf1ce1
Update packages/react/src/Checkbox/Checkbox.tsx
iansan5653 Mar 10, 2026
006cc27
Update useCombinedRefs to useMergedRefs
iansan5653 Mar 17, 2026
12abb13
Merge branch 'main' of https://github.com/primer/react into replace-u…
iansan5653 Mar 24, 2026
196c083
Fix a few renames
iansan5653 Mar 24, 2026
6e410b6
Somehow I missed some spots???
iansan5653 Mar 24, 2026
a09ae22
anchorref > anchorRef
iansan5653 Mar 24, 2026
90e9941
Revert some files because of a valid use case
iansan5653 Mar 24, 2026
dda4382
Update `useProvidedRefOrCreate` to remove deprecation comment
iansan5653 Mar 24, 2026
f86b058
Don't return a callback ref in React 18-
iansan5653 Mar 24, 2026
c0612a7
Update tests
iansan5653 Mar 24, 2026
072e5b9
Merge branch 'main' into replace-use-provided-ref-or-create
iansan5653 Mar 31, 2026
44e6850
Fix double import from merging
iansan5653 Mar 31, 2026
538f208
Merge branch 'main' of https://github.com/primer/react into replace-u…
iansan5653 Apr 8, 2026
607676a
Merge branch 'main' into replace-use-provided-ref-or-create
llastflowers Jun 26, 2026
bba5847
move merged ref update into useTabList after main refactor
llastflowers Jun 26, 2026
5afda49
fix merge conflict artifact
llastflowers Jun 26, 2026
cd349b0
fix merge conflict artifact
llastflowers Jun 26, 2026
75b228a
fix merge conflict artifact
llastflowers Jun 26, 2026
015347a
fix merge conflict artifact
llastflowers Jun 26, 2026
d30a7f0
fix more merge conflict artifacts
llastflowers Jun 26, 2026
2d40aaa
FilteredActionList updates to match main
llastflowers Jun 26, 2026
2c164e3
Fix AutocompleteInput blur handling with merged refs
llastflowers Jun 26, 2026
e032720
add back accidentally removed lint suppression
llastflowers Jun 26, 2026
fc78eed
ci fix
llastflowers Jun 26, 2026
d18507c
Fix Tabs ref types for useMergedRefs
llastflowers Jun 26, 2026
e88a6e5
Fix Tabs story ref usage with ActionList
llastflowers Jun 26, 2026
a72cd22
Fix Tabs story ActionList ref typing
llastflowers Jun 26, 2026
1c28af9
back last change out and try a different ci fix
llastflowers Jun 26, 2026
67c0f23
test(vrt): update snapshots
llastflowers Jun 26, 2026
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 5 additions & 5 deletions packages/react/src/ActionList/List.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import React, {type JSX} from 'react'
import React, {useRef, type JSX} from 'react'
import {fixedForwardRef} from '../utils/modern-polymorphic'
import {ActionListContainerContext} from './ActionListContainerContext'
import {useSlots} from '../hooks/useSlots'
import {Heading} from './Heading'
import {useId} from '../hooks/useId'
import {ListContext, type ActionListProps} from './shared'
import {useProvidedRefOrCreate} from '../hooks'
import {useMergedRefs} from '../hooks'
import {FocusKeys, useFocusZone} from '../hooks/useFocusZone'
import {clsx} from 'clsx'
import classes from './ActionList.module.css'
Expand Down Expand Up @@ -43,7 +43,8 @@ const UnwrappedList = <As extends React.ElementType = 'ul'>(

const ariaLabelledBy = slots.heading ? (slots.heading.props.id ?? headingId) : listLabelledBy
const listRole = role || listRoleFromContainer
const listRef = useProvidedRefOrCreate(forwardedRef as React.RefObject<HTMLUListElement>)
const listRef = useRef<HTMLElement>(null)
const mergedRef = useMergedRefs(forwardedRef, listRef)
const itemGapEnabled = useFeatureFlag('primer_react_action_list_item_gap') && container === 'NavList'

let enableFocusZone = false
Expand Down Expand Up @@ -100,12 +101,11 @@ const UnwrappedList = <As extends React.ElementType = 'ul'>(
return (
<ListContext.Provider value={listContextValue}>
{slots.heading}
{/* @ts-expect-error ref needs a non nullable ref */}
<Component
className={clsx(classes.ActionList, className)}
role={listRole}
aria-labelledby={ariaLabelledBy}
ref={listRef}
ref={mergedRef}
data-component="ActionList"
data-dividers={showDividers}
data-variant={variant}
Expand Down
9 changes: 4 additions & 5 deletions packages/react/src/AnchoredOverlay/AnchoredOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type {FocusTrapHookSettings} from '../hooks/useFocusTrap'
import {useFocusTrap} from '../hooks/useFocusTrap'
import type {FocusZoneHookSettings} from '../hooks/useFocusZone'
import {useFocusZone} from '../hooks/useFocusZone'
import {useAnchoredPosition, useProvidedRefOrCreate, useRenderForcingRef} from '../hooks'
import {useAnchoredPosition, useMergedRefs, useProvidedRefOrCreate, useRenderForcingRef} from '../hooks'
import {useId} from '../hooks/useId'
import type {AnchorPosition, PositionSettings} from '@primer/behaviors'
import {type ResponsiveValue} from '../hooks/useResponsiveValue'
Expand Down Expand Up @@ -207,6 +207,7 @@ export const AnchoredOverlay: React.FC<React.PropsWithChildren<AnchoredOverlayPr
setAnchorElement(anchorRef.current)
}
const [overlayRef, updateOverlayRef] = useRenderForcingRef<HTMLDivElement>()
const mergedOverlayRef = useMergedRefs(updateOverlayRef, overlayProps?.ref)
const [overlayElement, setOverlayElement] = useState<HTMLDivElement | null>(null)
const anchorId = useId(externalAnchorId)

Expand Down Expand Up @@ -436,12 +437,10 @@ export const AnchoredOverlay: React.FC<React.PropsWithChildren<AnchoredOverlayPr
{...(shouldRenderAsPopover ? {popover: 'manual'} : {})}
{...restOverlayProps}
{...(shouldRenderAsPopover ? {id: popoverId} : {})}
{...(cssAnchorPositioning ? {id: popoverId} : {})}
ref={node => {
if (overlayProps?.ref) {
assignRef(overlayProps.ref, node)
}
updateOverlayRef(node)
setOverlayElement(node)
assignRef(mergedOverlayRef, node)
}}
data-anchor-position={cssAnchorPositioning}
data-side={cssAnchorPositioning ? side : position?.anchorSide}
Expand Down
35 changes: 16 additions & 19 deletions packages/react/src/Autocomplete/AutocompleteInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,19 @@ const AutocompleteInput = React.forwardRef(

const handleInputBlur: FocusEventHandler<HTMLInputElement> = useCallback(
event => {
onBlur && onBlur(event)
onBlur?.(event)

// HACK: wait a tick and check the focused element before hiding the autocomplete menu
// this prevents the menu from hiding when the user is clicking an option in the Autoselect.Menu,
// but still hides the menu when the user blurs the input by tabbing out or clicking somewhere else on the page
// HACK: wait a tick before hiding the menu so click interactions can complete.
// Use the blur event's relatedTarget to determine whether focus is moving into the
// autocomplete menu; if not, hide the menu when focus leaves the input.
safeSetTimeout(() => {
if (document.activeElement !== inputRef.current) {
const nextFocusedElement = event.relatedTarget as Node | null
const menuElement = document.getElementById(`${id}-listbox`)

if (
!nextFocusedElement ||
(nextFocusedElement !== menuElement && !menuElement?.contains(nextFocusedElement))
) {
setShowMenu(false)

// Reset the input's value to the text the user actually typed rather than leaving the
Expand All @@ -75,11 +81,11 @@ const AutocompleteInput = React.forwardRef(
}
}, 0)
},
[onBlur, setShowMenu, inputRef, safeSetTimeout, autocompleteSuggestion, inputValue],
[onBlur, setShowMenu, inputRef, safeSetTimeout, autocompleteSuggestion, inputValue, id],
)

const handleInputChange: ChangeEventHandler<HTMLInputElement> = event => {
onChange && onChange(event)
onChange?.(event)
setInputValue(event.currentTarget.value)
if (!showMenu) {
setShowMenu(true)
Expand All @@ -88,7 +94,7 @@ const AutocompleteInput = React.forwardRef(

const handleInputKeyDown: KeyboardEventHandler<HTMLInputElement> = useCallback(
event => {
onKeyDown && onKeyDown(event)
onKeyDown?.(event)

if (event.key === 'Backspace') {
setHighlightRemainingText(false)
Expand All @@ -107,7 +113,7 @@ const AutocompleteInput = React.forwardRef(

const handleInputKeyUp: KeyboardEventHandler<HTMLInputElement> = useCallback(
event => {
onKeyUp && onKeyUp(event)
onKeyUp?.(event)

if (event.key === 'Backspace') {
setHighlightRemainingText(true)
Expand All @@ -118,12 +124,11 @@ const AutocompleteInput = React.forwardRef(

const onInputKeyPress: KeyboardEventHandler<HTMLInputElement> = useCallback(
event => {
onKeyPress && onKeyPress(event)
onKeyPress?.(event)
if (showMenu && event.key === 'Enter' && activeDescendantRef.current) {
event.preventDefault()
event.nativeEvent.stopImmediatePropagation()

// Forward Enter key press to active descendant so that item gets activated
const activeDescendantEvent = new KeyboardEvent(event.type, event.nativeEvent)
activeDescendantRef.current.dispatchEvent(activeDescendantEvent)
}
Expand All @@ -136,17 +141,10 @@ const AutocompleteInput = React.forwardRef(
return
}

// resets input value to being empty after a selection has been made
if (!autocompleteSuggestion) {
inputRef.current.value = inputValue
}

// TODO: fix bug where this function prevents `onChange` from being triggered if the highlighted item text
// is the same as what I'm typing
// e.g.: typing 'tw' highlights 'two', but when I 'two', the text input change does not get triggered
// Only apply the inline autocomplete suggestion while the input is focused. Without this guard,
// the suggestion can be re-applied to the DOM after the input is blurred, which would restore
// the full suggestion the user was editing away from. See https://github.com/primer/react/issues/4275
const isInputFocused = document.activeElement === inputRef.current

if (
Expand All @@ -163,7 +161,6 @@ const AutocompleteInput = React.forwardRef(
}
}

// calling this useEffect when `highlightRemainingText` changes breaks backspace functionality
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [autocompleteSuggestion, inputValue, inputRef, isMenuDirectlyActivated])

Expand Down
10 changes: 5 additions & 5 deletions packages/react/src/ButtonGroup/ButtonGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, {type PropsWithChildren} from 'react'
import React, {useRef, type PropsWithChildren} from 'react'
import classes from './ButtonGroup.module.css'
import {clsx} from 'clsx'
import {FocusKeys, useFocusZone} from '../hooks/useFocusZone'
import {useProvidedRefOrCreate} from '../hooks'
import {useMergedRefs} from '../hooks'
import type {ForwardRefComponent as PolymorphicForwardRefComponent} from '../utils/polymorphic'

export type ButtonGroupProps = PropsWithChildren<{
Expand All @@ -16,12 +16,13 @@ const ButtonGroup = React.forwardRef(function ButtonGroup(
{as: BaseComponent = 'div', children, className, role, ...rest},
forwardRef,
) {
const buttonRef = useRef<HTMLDivElement>(null)
const mergedRef = useMergedRefs(buttonRef, forwardRef)
const buttons = React.Children.map(children, (child, index) => (
<div key={index} className={classes.Item}>
{child}
</div>
))
const buttonRef = useProvidedRefOrCreate(forwardRef as React.RefObject<HTMLDivElement | null>)

useFocusZone({
containerRef: buttonRef,
Expand All @@ -32,8 +33,7 @@ const ButtonGroup = React.forwardRef(function ButtonGroup(

return (
<BaseComponent
//@ts-expect-error it needs a non nullable ref
ref={buttonRef}
ref={mergedRef}
className={clsx(className, classes.ButtonGroup)}
role={role}
{...rest}
Expand Down
17 changes: 12 additions & 5 deletions packages/react/src/Checkbox/Checkbox.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import {clsx} from 'clsx'
import {useProvidedRefOrCreate} from '../hooks'
import React, {useContext, useEffect, type ChangeEventHandler, type InputHTMLAttributes, type ReactElement} from 'react'
import {useMergedRefs} from '../hooks'
import React, {
useContext,
useEffect,
useRef,
type ChangeEventHandler,
type InputHTMLAttributes,
type ReactElement,
} from 'react'
import useLayoutEffect from '../utils/useIsomorphicLayoutEffect'
import type {FormValidationStatus} from '../utils/types/FormValidationStatus'
import {CheckboxGroupContext} from '../CheckboxGroup/CheckboxGroupContext'
Expand Down Expand Up @@ -58,7 +65,8 @@ const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(
ref,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
): ReactElement<any> => {
const checkboxRef = useProvidedRefOrCreate(ref as React.RefObject<HTMLInputElement>)
const checkboxRef = useRef<HTMLInputElement>(null)
const mergedRef = useMergedRefs(checkboxRef, ref)
const checkboxGroupContext = useContext(CheckboxGroupContext)
const handleOnChange: ChangeEventHandler<HTMLInputElement> = e => {
checkboxGroupContext.onChange && checkboxGroupContext.onChange(e)
Expand All @@ -72,7 +80,7 @@ const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(
const inputProps = {
type: 'checkbox',
disabled,
ref: checkboxRef,
ref: mergedRef,
checked: indeterminate ? false : checked,
defaultChecked,
required,
Expand Down Expand Up @@ -103,7 +111,6 @@ const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(
}
})
return (
// @ts-expect-error inputProp needs a non nullable ref
<input
{...inputProps}
data-component={dataComponent ?? 'Checkbox'}
Expand Down
8 changes: 4 additions & 4 deletions packages/react/src/Dialog/Dialog.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, {useCallback, useEffect, useRef, useState, type CSSProperties, type SyntheticEvent} from 'react'
import type {ButtonProps} from '../Button'
import {Button, IconButton} from '../Button'
import {useMergedRefs, useOnEscapePress, useProvidedRefOrCreate} from '../hooks'
import {useMergedRefs, useOnEscapePress} from '../hooks'
import {useFocusTrap} from '../hooks/useFocusTrap'
import {XIcon} from '@primer/octicons-react'
import {useFocusZone} from '../hooks/useFocusZone'
Expand Down Expand Up @@ -484,7 +484,8 @@ const Footer = React.forwardRef<HTMLDivElement, StyledFooterProps>(function Foot
Footer.displayName = 'Dialog.Footer'

const Buttons: React.FC<React.PropsWithChildren<{buttons: DialogButtonProps[]}>> = ({buttons}) => {
const autoFocusRef = useProvidedRefOrCreate<HTMLButtonElement>(buttons.find(button => button.autoFocus)?.ref)
const autoFocusRef = useRef<HTMLButtonElement>(null)
const mergedRef = useMergedRefs(autoFocusRef, buttons.find(button => button.autoFocus)?.ref)
let autoFocusCount = 0
const [hasRendered, setHasRendered] = useState(0)
useEffect(() => {
Expand All @@ -508,8 +509,7 @@ const Buttons: React.FC<React.PropsWithChildren<{buttons: DialogButtonProps[]}>>
{...buttonProps}
// 'normal' value is equivalent to 'default', this is used for backwards compatibility
variant={buttonType === 'normal' ? 'default' : buttonType}
// @ts-expect-error it needs a non nullable ref
ref={autoFocus && autoFocusCount === 0 ? (autoFocusCount++, autoFocusRef) : null}
ref={autoFocus && autoFocusCount === 0 ? (autoFocusCount++, mergedRef) : null}
>
{content}
</Button>
Expand Down
16 changes: 8 additions & 8 deletions packages/react/src/FilteredActionList/FilteredActionList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {ActionList, type ActionListProps} from '../ActionList'
import type {GroupedListProps, ListPropsBase, ItemInput, RenderItemFn} from './'
import {useFocusZone} from '../hooks/useFocusZone'
import {useId} from '../hooks/useId'
import {useProvidedRefOrCreate} from '../hooks/useProvidedRefOrCreate'
import {useProvidedStateOrCreate} from '../hooks/useProvidedStateOrCreate'
import useScrollFlash from '../hooks/useScrollFlash'
import {VisuallyHidden} from '../VisuallyHidden'
Expand All @@ -21,6 +20,7 @@ import {isValidElementType} from 'react-is'
import {useAnnouncements} from './useAnnouncements'
import {clsx} from 'clsx'
import {useVirtualizer} from '@tanstack/react-virtual'
import {useMergedRefs} from '../hooks'
import {FilteredActionListInput} from './FilteredActionListInput'

const menuScrollMargins: ScrollIntoViewOptions = {startMargin: 0, endMargin: 8}
Expand Down Expand Up @@ -189,10 +189,11 @@ export function FilteredActionList({
const inputAndListContainerRef = useRef<HTMLDivElement>(null)
const listRef = useRef<HTMLUListElement>(null)

const scrollContainerRef = useProvidedRefOrCreate<HTMLDivElement>(
providedScrollContainerRef as React.RefObject<HTMLDivElement>,
)
const inputRef = useProvidedRefOrCreate<HTMLInputElement>(providedInputRef)
const scrollContainerRef = useRef<HTMLDivElement>(null)
const combinedScrollContainerRef = useMergedRefs(scrollContainerRef, providedScrollContainerRef)

const inputRef = useRef<HTMLInputElement>(null)
const combinedInputRef = useMergedRefs(inputRef, providedInputRef)

const usingRovingTabindex = _PrivateFocusManagement === 'roving-tabindex'
const [listContainerElement, setListContainerElement] = useState<HTMLUListElement | null>(null)
Expand Down Expand Up @@ -559,7 +560,7 @@ export function FilteredActionList({
data-component="FilteredActionList"
>
<FilteredActionListInput
inputRef={inputRef}
inputRef={combinedInputRef}
value={filterValue}
onInputChange={onInputChange}
onInputKeyPress={onInputKeyPress}
Expand Down Expand Up @@ -591,8 +592,7 @@ export function FilteredActionList({
</label>
</div>
)}
{/* @ts-expect-error div needs a non nullable ref */}
<div ref={scrollContainerRef} className={classes.Container}>
<div ref={combinedScrollContainerRef} className={classes.Container}>
{getBodyContent()}
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type {TextInputProps} from '../TextInput'
import classes from './FilteredActionList.module.css'

export interface FilteredActionListInputProps extends Partial<Omit<TextInputProps, 'onChange' | 'onKeyDown'>> {
inputRef: React.RefObject<HTMLInputElement | null>
inputRef: React.Ref<HTMLInputElement | null>
onInputChange?: (e: React.ChangeEvent<HTMLInputElement>) => void
onInputKeyPress?: React.KeyboardEventHandler<HTMLInputElement>
onInputKeyDown?: React.KeyboardEventHandler<HTMLInputElement>
Expand Down
13 changes: 6 additions & 7 deletions packages/react/src/PageHeader/PageHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useEffect} from 'react'
import React, {useEffect, useRef} from 'react'
import type {ResponsiveValue} from '../hooks/useResponsiveValue'
import {isResponsiveValue} from '../hooks/useResponsiveValue'
import Heading from '../Heading'
Expand All @@ -10,7 +10,7 @@ import {getResponsiveAttributes} from '../internal/utils/getResponsiveAttributes
import type {ForwardRefComponent as PolymorphicForwardRefComponent} from '../utils/polymorphic'
import {areAllValuesTheSame, haveRegularAndWideSameValue} from '../utils/getBreakpointDeclarations'
import {warning} from '../utils/warning'
import {useProvidedRefOrCreate} from '../hooks'
import {useMergedRefs} from '../hooks'
import type {AriaRole, FCWithSlotMarker} from '../utils/types'
import {clsx} from 'clsx'

Expand Down Expand Up @@ -49,7 +49,8 @@ export type PageHeaderProps = {

const Root = React.forwardRef<HTMLDivElement, React.PropsWithChildren<PageHeaderProps>>(
({children, className, as: BaseComponent = 'div', 'aria-label': ariaLabel, role, hasBorder}, forwardedRef) => {
const rootRef = useProvidedRefOrCreate<HTMLDivElement>(forwardedRef as React.RefObject<HTMLDivElement>)
const rootRef = useRef<HTMLDivElement>(null)
const mergedRef = useMergedRefs(rootRef, forwardedRef)

const isInteractive = (element: HTMLElement) => {
return (
Expand Down Expand Up @@ -105,7 +106,7 @@ const Root = React.forwardRef<HTMLDivElement, React.PropsWithChildren<PageHeader

return (
<BaseComponent
ref={rootRef}
ref={mergedRef}
className={clsx(classes.PageHeader, className)}
data-component="PageHeader"
data-has-border={hasBorder ? 'true' : undefined}
Expand Down Expand Up @@ -220,12 +221,10 @@ export type TitleAreaProps = {

const TitleArea = React.forwardRef<HTMLDivElement, React.PropsWithChildren<TitleAreaProps>>(
({children, className, hidden = false, variant = 'medium'}, forwardedRef) => {
const titleAreaRef = useProvidedRefOrCreate<HTMLDivElement>(forwardedRef as React.RefObject<HTMLDivElement>)
return (
<div
className={clsx(classes.TitleArea, className)}
// @ts-expect-error it needs a non nullable ref
ref={titleAreaRef}
ref={forwardedRef}
data-component="TitleArea"
{...getResponsiveAttributes('size-variant', variant)}
{...getHiddenDataAttributes(hidden)}
Expand Down
Loading
Loading