11import * as Solid from 'solid-js'
2- import { isServer } from 'solid-js/web'
32
43export interface ClientOnlyProps {
54 /**
6- * The children to render if the JS is loaded.
5+ * The children to render when the JS is loaded.
76 */
87 children : Solid . JSX . Element
98 /**
@@ -30,9 +29,37 @@ export interface ClientOnlyProps {
3029 * ```
3130 */
3231export function ClientOnly ( props : ClientOnlyProps ) {
32+ const hydrated = useHydrated ( )
3333 return (
34- < Solid . Show when = { ! isServer } fallback = { props . fallback } >
34+ < Solid . Show when = { hydrated ( ) } fallback = { props . fallback ?? null } >
3535 < > { props . children } </ >
3636 </ Solid . Show >
3737 )
3838}
39+
40+ /**
41+ * Return a boolean indicating if the JS has been hydrated already.
42+ * When doing Server-Side Rendering, the result will always be false.
43+ * When doing Client-Side Rendering, the result will always be false on the
44+ * first render and true from then on. Even if a new component renders it will
45+ * always start with true.
46+ *
47+ * @example
48+ * ```tsx
49+ * // Disable a button that needs JS to work.
50+ * const hydrated = useHydrated()
51+ * return (
52+ * <button type="button" disabled={!hydrated()} onClick={doSomethingCustom}>
53+ * Click me
54+ * </button>
55+ * )
56+ * ```
57+ * @returns True if the JS has been hydrated already, false otherwise.
58+ */
59+ function useHydrated ( ) : Solid . Accessor < boolean > {
60+ const [ hydrated , setHydrated ] = Solid . createSignal ( false )
61+ Solid . onMount ( ( ) => {
62+ setHydrated ( true )
63+ } )
64+ return hydrated
65+ }
0 commit comments