diff --git a/packages/ui/src/Radio/Radio.tsx b/packages/ui/src/Radio/Radio.tsx index ac8d1b7..a6f67c6 100644 --- a/packages/ui/src/Radio/Radio.tsx +++ b/packages/ui/src/Radio/Radio.tsx @@ -1,5 +1,5 @@ import { cn } from '@tpmjs/utils/cn'; -import { forwardRef } from 'react'; +import { forwardRef, useEffect } from 'react'; import { useRadioGroup } from './RadioGroup'; import type { RadioProps } from './types'; import { radioDotVariants, radioLabelVariants, radioUIVariants, radioVariants } from './variants'; @@ -44,6 +44,15 @@ export const Radio = forwardRef( // Get context from RadioGroup const context = useRadioGroup(); + // Validate context is available after hydration (only in development) + useEffect(() => { + if (process.env.NODE_ENV !== 'production' && !context.name) { + console.error( + 'Radio must be used within a RadioGroup. If you see this error, ensure your Radio components are wrapped in a RadioGroup component.' + ); + } + }, [context.name]); + // Merge props with context (props take precedence) const state = stateProp ?? context.state ?? 'default'; const size = sizeProp ?? context.size ?? 'md'; diff --git a/packages/ui/src/Radio/RadioGroup.tsx b/packages/ui/src/Radio/RadioGroup.tsx index 53a1dfd..c6c6ca3 100644 --- a/packages/ui/src/Radio/RadioGroup.tsx +++ b/packages/ui/src/Radio/RadioGroup.tsx @@ -1,5 +1,5 @@ import { cn } from '@tpmjs/utils/cn'; -import { createContext, useContext } from 'react'; +import { createContext, useContext, useEffect } from 'react'; import { useControlled } from '../system/useControlled'; import type { RadioGroupContextValue, RadioGroupProps } from './types'; import { radioGroupVariants } from './variants'; @@ -15,20 +15,16 @@ export const RadioGroupContext = createContext(nu export const useRadioGroup = () => { const context = useContext(RadioGroupContext); if (!context) { - // During SSR/prerendering, context might not be available yet - // Return default values to prevent build errors - if (typeof window === 'undefined') { - return { - name: '', - value: undefined, - onChange: () => {}, - state: 'default' as const, - size: 'md' as const, - disabled: false, - }; - } - // In browser, this is a real error - throw new Error('Radio must be used within a RadioGroup'); + // Return default values for SSR and hydration compatibility + // This prevents hydration mismatches while allowing the component to render + return { + name: '', + value: undefined, + onChange: () => {}, + state: 'default' as const, + size: 'md' as const, + disabled: false, + }; } return context; };