From 0cf2fbc6ffa6a8b3a2bd78edb24037f8bbff2f4d Mon Sep 17 00:00:00 2001 From: Marie Lucca Date: Thu, 25 Jun 2026 00:07:13 -0400 Subject: [PATCH 1/3] graduate primer_react_theme_provider_remove_ssr_handoff ff --- .../src/FeatureFlags/DefaultFeatureFlags.ts | 1 - packages/react/src/ThemeProvider.tsx | 61 +------------------ .../src/__tests__/ThemeProvider.test.tsx | 58 ------------------ 3 files changed, 3 insertions(+), 117 deletions(-) diff --git a/packages/react/src/FeatureFlags/DefaultFeatureFlags.ts b/packages/react/src/FeatureFlags/DefaultFeatureFlags.ts index 2b1f5d81a42..763a96df96a 100644 --- a/packages/react/src/FeatureFlags/DefaultFeatureFlags.ts +++ b/packages/react/src/FeatureFlags/DefaultFeatureFlags.ts @@ -8,5 +8,4 @@ export const DefaultFeatureFlags = FeatureFlagScope.create({ primer_react_action_list_group_heading_trailing_action: false, primer_react_action_list_item_gap: false, primer_react_timeline_list_semantics: false, - primer_react_theme_provider_remove_ssr_handoff: false, }) diff --git a/packages/react/src/ThemeProvider.tsx b/packages/react/src/ThemeProvider.tsx index c2876ed7fc5..7c3cb8cf2f7 100644 --- a/packages/react/src/ThemeProvider.tsx +++ b/packages/react/src/ThemeProvider.tsx @@ -1,8 +1,6 @@ import React from 'react' import defaultTheme from './theme' import deepmerge from 'deepmerge' -import {useId} from './hooks' -import {useFeatureFlag} from './FeatureFlags' import {useSyncedState} from './hooks/useSyncedState' import {ThemeContext} from './ThemeContext' import {useTheme} from './useTheme' @@ -21,7 +19,7 @@ export type ThemeProviderProps = { dayScheme?: string nightScheme?: string /** - * No-op when the `primer_react_theme_provider_remove_ssr_handoff` feature flag is enabled. + * @deprecated This prop is no longer used and has no effect. */ preventSSRMismatch?: boolean /** @@ -32,33 +30,6 @@ export type ThemeProviderProps = { contextOnly?: boolean } -// inspired from __NEXT_DATA__, we use application/json to avoid CSRF policy with inline scripts -const serverHandoffCache = new Map>() -const emptyHandoff: Record = {} -const getServerHandoff = (id: string) => { - if (typeof document === 'undefined') return emptyHandoff - - const cached = serverHandoffCache.get(id) - if (cached !== undefined) return cached - - try { - const serverData = document.getElementById(`__PRIMER_DATA_${id}__`)?.textContent - if (serverData) { - const parsed = JSON.parse(serverData) - serverHandoffCache.set(id, parsed) - return parsed - } - } catch (_error) { - // if document/element does not exist or JSON is invalid, suppress error - } - - const empty = {} - serverHandoffCache.set(id, empty) - return empty -} - -const emptySubscribe = () => () => {} - export const ThemeProvider: React.FC> = ({children, ...props}) => { // Get fallback values from parent ThemeProvider (if exists) const { @@ -71,22 +42,11 @@ export const ThemeProvider: React.FC // Initialize state const theme = fallbackTheme ?? defaultTheme - const removeSSRHandoff = useFeatureFlag('primer_react_theme_provider_remove_ssr_handoff') - const uniqueDataId = useId() - const [colorMode, setColorMode] = useSyncedState(props.colorMode ?? fallbackColorMode ?? defaultColorMode) const [dayScheme, setDayScheme] = useSyncedState(props.dayScheme ?? fallbackDayScheme ?? defaultDayScheme) const [nightScheme, setNightScheme] = useSyncedState(props.nightScheme ?? fallbackNightScheme ?? defaultNightScheme) const systemColorMode = useSystemColorMode() - const clientColorMode = resolveColorMode(colorMode, systemColorMode) - // During SSR/hydration, use the server-rendered color mode from the handoff script tag - // to avoid mismatches. After hydration, resolve from client state. - const ssrResolvedColorMode = React.useSyncExternalStore( - emptySubscribe, - () => clientColorMode, - () => getServerHandoff(uniqueDataId).resolvedServerColorMode ?? clientColorMode, - ) - const resolvedColorMode = removeSSRHandoff ? clientColorMode : ssrResolvedColorMode + const resolvedColorMode = resolveColorMode(colorMode, systemColorMode) const colorScheme = chooseColorScheme(resolvedColorMode, dayScheme, nightScheme) const {resolvedTheme, resolvedColorScheme} = React.useMemo( () => applyColorScheme(theme, colorScheme), @@ -120,22 +80,8 @@ export const ThemeProvider: React.FC ], ) - const ssrHandoffScript = - !removeSSRHandoff && props.preventSSRMismatch ? ( -