ClientOnly

Provided by: UI framework Vike extension (vike-react/vike-vue/vike-solid) (or yourself).

The <ClientOnly> wrapper enables you to render and load a component only on the client-side.

Alternatively, you can set ssr: false to render and load the entire page only on the client-side.

Common use cases:

  • Library components that don't support SSR. A solution is to render and load the component only on the client-side.

    Most component libraries nowadays support SSR but some don't. Some even crash when they're merely loaded on the server-side (for example if the library has a hard reference to browser-only APIs/objects such as window).

  • Performance. <ClientOnly> allows you to defer loading heavy components, such as a complex interactive map. That way, your users can already interact with your page before even the browser starts loading that heavy component.

    Vite code-splits dynamic imports such as const { SomeComponent } = await import('./SomeComponent'). In other words, the code of <SomeComponent /> isn't included in the initial JavaScript client bundle: it's loaded only when/if import() is called.

React

Usage

import { ClientOnly } from 'vike-react/ClientOnly'

function MapWrapper({ someProp }) {
  return (
    <ClientOnly
      load={() => import('./MyComponent.jsx')}
      /* Or:
      load={async () => (await import('some-library')).SomeComponent}
      */
      fallback={<Loading />}
      // Re-render if someProp changes
      deps={[someProp]}
    >
      {(MyComponent) => <MyComponent someProp={someProp} />}
    </ClientOnly>
  )
}

Props

  • load: The function that imports the component.
  • children: The function that renders the component.
  • fallback: The element that is displayed while the component is being loaded.
  • deps (optional): An array of dependencies that, when changed, triggers a re-render of the component. The deps prop of <ClientOnly> is passed as-is to the dependencies parameter of React's useEffect() hook.

Solid

Usage

import { ClientOnly } from 'vike-solid/ClientOnly'

function MyComponent(props) {
  return (
    <ClientOnly
      load={() => import('./MyComponent.jsx')}
      /* Or:
      load={async () => (await import('some-library')).SomeComponent}
      */
      fallback={<Loading />}
    >
      {(MyComponent) => <MyComponent {...props} />}
    </ClientOnly>
  )
}

Props

  • load: The function that imports the component.
  • children: The function that renders the component.
  • fallback: The element that is displayed while the component is being loaded.

Vue

Usage

<template>
  <ClientOnly :load="() => import('./MyComponent.vue')">
  <!-- Or:
  <ClientOnly :load="() => (await import('some-library')).SomeComponent">
  -->
    <template #fallback>Loading...</template>
  </ClientOnly>
</template>

<script setup>
import ClientOnly from 'vike-vue/ClientOnly'
</script>

Slots

  • fallback: The component that is displayed while the dynamic component is being loaded.

Props

All props are passed to the loaded component (except load). Type inference doesn't work as of now, see vike-vue#67.

  • load: The function that imports the component.

Without Vike extension

In case you don't use a UI framework Vike extension (vike-react/vike-vue/vike-solid), you can implement <ClientOnly> yourself.

Examples: