> ## Documentation Index
> Fetch the complete documentation index at: https://inertiajs.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Load When Visible

<Warning>You are viewing the documentation for Inertia.js v2. Inertia.js v3 has been released and is now the default version. Please visit the [upgrade guide](/v3/getting-started/upgrade-guide) to get started.</Warning>

Inertia supports lazy loading data on scroll using the Intersection Observer API. It provides the `WhenVisible` component as a convenient way to load data when an element becomes visible in the viewport.

The `WhenVisible` component accepts a `data` prop that specifies the key of the prop to load. It also accepts a `fallback` prop that specifies a component to render while the data is loading. The `WhenVisible` component should wrap the component that depends on the data.

<CodeGroup>
  ```vue Vue icon="vuejs" theme={null}
  <script setup>
  import { WhenVisible } from '@inertiajs/vue3'
  </script>

  <template>
      <WhenVisible data="permissions">
          <template #fallback>
              <div>Loading...</div>
          </template>

          <div v-for="permission in permissions">
              <!-- ... -->
          </div>
      </WhenVisible>
  </template>
  ```

  ```jsx React icon="react" theme={null}
  import { WhenVisible } from '@inertiajs/react'

  export default () => (
      <WhenVisible data="permissions" fallback={() => <div>Loading...</div>}>
          <PermissionsChildComponent />
      </WhenVisible>
  )
  ```

  ```svelte Svelte 4 icon="s" theme={null}
  <script>
      import { WhenVisible } from '@inertiajs/svelte'

      export let permissions
  </script>

  <WhenVisible data="permissions">
      <svelte:fragment slot="fallback">
          <div>Loading...</div>
      </svelte:fragment>

      {#each permissions as permission}
          <!-- ... -->
      {/each}
  </WhenVisible>
  ```

  ```svelte Svelte 5 icon="s" theme={null}
  <script>
      import { WhenVisible } from '@inertiajs/svelte'

      let { permissions } = $props()
  </script>

  <WhenVisible data="permissions">
      {#snippet fallback()}
          <div>Loading...</div>
      {/snippet}

      {#each permissions as permission}
          <!-- ... -->
      {/each}
  </WhenVisible>
  ```
</CodeGroup>

If you'd like to load multiple props when an element becomes visible, you can provide an array to the `data` prop.

<CodeGroup>
  ```vue Vue icon="vuejs" theme={null}
  <script setup>
  import { WhenVisible } from '@inertiajs/vue3'
  </script>

  <template>
      <WhenVisible :data="['teams', 'users']">
          <template #fallback>
              <div>Loading...</div>
          </template>

          <!-- Props are now loaded -->
      </WhenVisible>
  </template>
  ```

  ```jsx React icon="react" theme={null}
  import { WhenVisible } from '@inertiajs/react'

  export default () => (
      <WhenVisible data={['teams', 'users']} fallback={() => <div>Loading...</div>}>
          <ChildComponent />
      </WhenVisible>
  )
  ```

  ```svelte Svelte 4 icon="s" theme={null}
  <script>
      import { WhenVisible } from '@inertiajs/svelte'

      export let teams
      export let users
  </script>

  <WhenVisible data={['teams', 'users']}>
      <svelte:fragment slot="fallback">
          <div>Loading...</div>
      </svelte:fragment>

      <!-- Props are now loaded -->
  </WhenVisible>
  ```

  ```svelte Svelte 5 icon="s" theme={null}
  <script>
      import { WhenVisible } from '@inertiajs/svelte'

      let { teams, users } = $props()
  </script>

  <WhenVisible data={['teams', 'users']}>
      {#snippet fallback()}
          <div>Loading...</div>
      {/snippet}

      <!-- Props are now loaded -->
  </WhenVisible>
  ```
</CodeGroup>

## Loading Before Visible

If you'd like to start loading data before the element is visible, you can provide a value to the `buffer` prop. The buffer value is a number that represents the number of pixels before the element is visible.

<CodeGroup>
  ```vue Vue icon="vuejs" theme={null}
  <script setup>
  import { WhenVisible } from '@inertiajs/vue3'
  </script>

  <template>
      <WhenVisible data="permissions" :buffer="500">
          <template #fallback>
              <div>Loading...</div>
          </template>

          <div v-for="permission in permissions">
              <!-- ... -->
          </div>
      </WhenVisible>
  </template>
  ```

  ```jsx React icon="react" theme={null}
  import { WhenVisible } from '@inertiajs/react'

  export default () => (
      <WhenVisible data="permissions" buffer={500} fallback={() => <div>Loading...</div>}>
          <PermissionsChildComponent />
      </WhenVisible>
  )
  ```

  ```svelte Svelte 4 icon="s" theme={null}
  <script>
      import { WhenVisible } from '@inertiajs/svelte'

      export let permissions
  </script>

  <WhenVisible data="permissions" buffer={500}>
      <svelte:fragment slot="fallback">
          <div>Loading...</div>
      </svelte:fragment>

      {#each permissions as permission}
          <!-- ... -->
      {/each}
  </WhenVisible>
  ```

  ```svelte Svelte 5 icon="s" theme={null}
  <script>
      import { WhenVisible } from '@inertiajs/svelte'

      let { permissions } = $props()
  </script>

  <WhenVisible data="permissions" buffer={500}>
      {#snippet fallback()}
          <div>Loading...</div>
      {/snippet}

      {#each permissions as permission}
          <!-- ... -->
      {/each}
  </WhenVisible>
  ```
</CodeGroup>

In the above example, the data will start loading 500 pixels before the element is visible.

By default, the `WhenVisible` component wraps the fallback template in a `div` element so it can ensure the element is visible in the viewport. If you want to customize the wrapper element, you can provide the `as` prop.

<CodeGroup>
  ```vue Vue icon="vuejs" theme={null}
  <script setup>
  import { WhenVisible } from '@inertiajs/vue3'
  </script>

  <template>
      <WhenVisible data="products" as="span">
          <!-- ... -->
      </WhenVisible>
  </template>
  ```

  ```jsx React icon="react" theme={null}
  import { WhenVisible } from '@inertiajs/react'

  export default () => (
      <WhenVisible data="products" as="span">
          <ProductsChildComponent />
      </WhenVisible>
  )
  ```

  ```svelte Svelte 4 icon="s" theme={null}
  <script>
      import { WhenVisible } from '@inertiajs/svelte'

      export let products
  </script>

  <WhenVisible data="products" as="span">
      <!-- ... -->
  </WhenVisible>
  ```

  ```svelte Svelte 5 icon="s" theme={null}
  <script>
      import { WhenVisible } from '@inertiajs/svelte'

      let { products } = $props()
  </script>

  <WhenVisible data="products" as="span">
      <!-- ... -->
  </WhenVisible>
  ```
</CodeGroup>

## Always Trigger

By default, the `WhenVisible` component will only trigger once when the element becomes visible. If you want to always trigger the data loading when the element is visible, you can provide the `always`prop.

This is useful when you want to load data every time the element becomes visible, such as when the element is at the end of an infinite scroll list and you want to load more data. Alternatively, you can use the [Infinite scroll](/v2/data-props/infinite-scroll) component which handles this use case for you.

Note that if the data loading request is already in flight, the component will wait until it is finished to start the next request if the element is still visible in the viewport.

<CodeGroup>
  ```vue Vue icon="vuejs" theme={null}
  <script setup>
  import { WhenVisible } from '@inertiajs/vue3'
  </script>

  <template>
      <WhenVisible data="products" always>
          <!-- ... -->
      </WhenVisible>
  </template>
  ```

  ```jsx React icon="react" theme={null}
  import { WhenVisible } from '@inertiajs/react'

  export default () => (
      <WhenVisible data="products" always>
          <ProductsChildComponent />
      </WhenVisible>
  )
  ```

  ```svelte Svelte 4 icon="s" theme={null}
  <script>
      import { WhenVisible } from '@inertiajs/svelte'

      export let products
  </script>

  <WhenVisible data="products" always>
      <!-- ... -->
  </WhenVisible>
  ```

  ```svelte Svelte 5 icon="s" theme={null}
  <script>
      import { WhenVisible } from '@inertiajs/svelte'

      let { products } = $props()
  </script>

  <WhenVisible data="products" always>
      <!-- ... -->
  </WhenVisible>
  ```
</CodeGroup>

### Fetching State

The `WhenVisible` component exposes a `fetching` slot prop that you may use to display a loading indicator during subsequent requests. This is useful because the `fallback` is only shown on the initial load, while `fetching` allows you to indicate that data is being refreshed on subsequent loads.

<CodeGroup>
  ```vue Vue icon="vuejs" theme={null}
  <script setup>
  import { WhenVisible } from '@inertiajs/vue3'
  </script>

  <template>
      <WhenVisible data="permissions" always>
          <template #default="{ fetching }">
              <PermissionsChildComponent />
              <div v-if="fetching">Refreshing...</div>
          </template>

          <template #fallback>
              <div>Loading...</div>
          </template>
      </WhenVisible>
  </template>
  ```

  ```jsx React icon="react" theme={null}
  import { WhenVisible } from '@inertiajs/react'

  export default () => (
      <WhenVisible data="permissions" always fallback={() => <div>Loading...</div>}>
          {({ fetching }) => (
              <>
                  <PermissionsChildComponent />
                  {fetching && <div>Refreshing...</div>}
              </>
          )}
      </WhenVisible>
  )
  ```

  ```svelte Svelte 4 icon="s" theme={null}
  <script>
      import { WhenVisible } from '@inertiajs/svelte'

      export let permissions
  </script>

  <WhenVisible data="permissions" always let:fetching>
      <PermissionsChildComponent />
      {#if fetching}
          <div>Refreshing...</div>
      {/if}

      <svelte:fragment slot="fallback">
          <div>Loading...</div>
      </svelte:fragment>
  </WhenVisible>
  ```

  ```svelte Svelte 5 icon="s" theme={null}
  <script>
      import { WhenVisible } from '@inertiajs/svelte'

      let { permissions } = $props()
  </script>

  <WhenVisible data="permissions" always let:fetching>
      <PermissionsChildComponent />
      {#if fetching}
          <div>Refreshing...</div>
      {/if}

      {#snippet fallback()}
          <div>Loading...</div>
      {/snippet}
  </WhenVisible>
  ```
</CodeGroup>

## Form Submissions

When submitting forms, you may want to use the `except` option to exclude the props that are being used by the `WhenVisible` component. This prevents the props from being reloaded when you get redirected back to the current page because of validation errors.

<CodeGroup>
  ```vue Vue icon="vuejs" theme={null}
  <script setup>
  import { useForm, WhenVisible } from '@inertiajs/vue3'

  const form = useForm({
      name: '',
      email: '',
  })

  function submit() {
      form.post('/users', {
          except: ['permissions'],
      })
  }
  </script>

  <template>
      <form @submit.prevent="submit">
          <!-- ... -->
      </form>

      <WhenVisible data="permissions">
          <!-- ... -->
      </WhenVisible>
  </template>
  ```

  ```jsx React icon="react" theme={null}
  import { useForm, WhenVisible } from '@inertiajs/react'

  export default function CreateUser() {
      const { data, setData, post } = useForm({
          name: '',
          email: '',
      })

      function submit(e) {
          e.preventDefault()
          post('/users', {
              except: ['permissions'],
          })
      }

      return (
          <>
              <form onSubmit={submit}>
                  {/* ... */}
              </form>

              <WhenVisible data="permissions">
                  {/* ... */}
              </WhenVisible>
          </>
      )
  }
  ```

  ```svelte Svelte 4 icon="s" theme={null}
  <script>
      import { useForm, WhenVisible } from '@inertiajs/svelte'

      const form = useForm({
          name: '',
          email: '',
      })

      function submit() {
          $form.post('/users', {
              except: ['permissions'],
          })
      }
  </script>

  <form on:submit|preventDefault={submit}>
      <!-- ... -->
  </form>

  <WhenVisible data="permissions">
      <!-- ... -->
  </WhenVisible>
  ```

  ```svelte Svelte 5 icon="s" theme={null}
  <script>
      import { useForm, WhenVisible } from '@inertiajs/svelte'

      const form = useForm({
          name: '',
          email: '',
      })

      function submit() {
          form.post('/users', {
              except: ['permissions'],
          })
      }
  </script>

  <form onsubmit={submit}>
      <!-- ... -->
  </form>

  <WhenVisible data="permissions">
      <!-- ... -->
  </WhenVisible>
  ```
</CodeGroup>
