Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 90 additions & 86 deletions docs/content/docs/1.guides/1.script-triggers.md
Original file line number Diff line number Diff line change
@@ -1,52 +1,56 @@
---
title: Triggering Script Loading
title: Script Triggers
description: Control when scripts load with Nuxt Scripts' flexible trigger system.
---

Nuxt Scripts provides several ways to trigger the loading of scripts.
Nuxt Scripts provides a flexible trigger system to control when scripts load, helping you optimize performance by loading scripts at the right moment for your users.

::code-group
## Default: onNuxtReady

```ts [useScript - Ref]
import { useTimeout } from '@vueuse/core'
By default, scripts use the `onNuxtReady` trigger, providing "idle loading" behavior where scripts load only after the page is fully interactive. This minimizes impact on Core Web Vitals and user experience.

const { ready } = useTimeout(3000)
useScript({
src: 'https://example.com/script.js',
}, {
// load however you like!
trigger: ready, // refs supported
The `onNuxtReady` trigger ensures scripts load:
- After Nuxt hydration is complete
- When the browser is idle and the main thread is available
- Without blocking critical page rendering or user interactions

```ts
// Default behavior - explicit for clarity
useScript('https://widget.intercom.io/widget/abc123', {
trigger: 'onNuxtReady'
})
```

```ts [useScript - Computed]
const route = useRoute()
useScript({
src: 'https://example.com/script.js',
}, {
// only if route has a specific query
trigger: computed(() => !!route.query.affiliateId),
// Registry scripts also use onNuxtReady by default
useScriptGoogleAnalytics({
id: 'GA_MEASUREMENT_ID'
// trigger: 'onNuxtReady' is implied
})
```

```ts [Registry Script]
import { useTimeout } from '@vueuse/core'
You can change this default by modifying the [defaultScriptOptions](/docs/api/nuxt-config#defaultscriptoptions).

const { ready } = useTimeout(3000)
useScriptMetaPixel({
id: '1234567890',
scriptOptions: {
trigger: ready
}
## Specialized Triggers

### Idle Timeout

Use [useScriptTriggerIdleTimeout](/docs/api/use-script-trigger-idle-timeout) to delay script loading for a specified time after Nuxt is ready:

::code-group

```ts [Composable]
useScript('https://example.com/analytics.js', {
trigger: useScriptTriggerIdleTimeout({ timeout: 5000 })
})
```

```ts [Global Script]
```ts [nuxt.config.ts]
export default defineNuxtConfig({
scripts: {
globals: {
myScript: ['https://example.com/script.js', {
// load after page is fully interactive (idle loading)
trigger: 'onNuxtReady'
registry: {
googleAnalytics: [{
id: 'GA_MEASUREMENT_ID'
}, {
trigger: { idleTimeout: 3000 }
}]
}
}
Expand All @@ -55,93 +59,93 @@ export default defineNuxtConfig({

::

## Default Behavior

By default, scripts are loaded when Nuxt is fully hydrated using the `onNuxtReady` trigger. This provides an "idle loading" behavior where scripts load only after the page is fully interactive, minimizing impact on Core Web Vitals and user experience.

The `onNuxtReady` trigger ensures scripts load:
- After Nuxt hydration is complete
- When the browser is idle and the main thread is available
- Without blocking critical page rendering or user interactions

This is more effective than using `defer` or `fetchpriority="low"` attributes alone, as it waits for the application to be fully ready rather than just the HTML parsing to complete.

You can change this default by modifying the [defaultScriptOptions](/docs/api/nuxt-config#defaultscriptoptions).
### User Interaction

## Idle Loading with onNuxtReady
Use [useScriptTriggerInteraction](/docs/api/use-script-trigger-interaction) to load scripts when users interact with your site:

The `onNuxtReady` trigger is perfect for non-critical scripts like chat widgets, analytics, or marketing tools that should load with minimal performance impact:
::code-group

```ts
// Chat widget - loads after page is fully interactive
useScript('https://widget.intercom.io/widget/abc123', {
trigger: 'onNuxtReady' // default behavior
```ts [Composable]
useScript('https://example.com/chat-widget.js', {
trigger: useScriptTriggerInteraction({
events: ['scroll', 'click', 'keydown']
})
})
```

// Explicitly using onNuxtReady for clarity
useScriptGoogleAnalytics({
id: 'GA_MEASUREMENT_ID',
scriptOptions: {
trigger: 'onNuxtReady'
```ts [nuxt.config.ts]
export default defineNuxtConfig({
scripts: {
globals: {
chatWidget: ['https://widget.example.com/chat.js', {
trigger: { interaction: ['scroll', 'click', 'touchstart'] }
}]
}
}
})
```

This approach ensures your Core Web Vitals remain optimal while still loading necessary third-party scripts.
::

## Element Event Triggers
### Element Events

The [useScriptTriggerElement](/docs/api/use-script-trigger-element) composable allows you to hook into element events as a way to load script. This is useful for loading scripts when a user interacts with a specific element.
Use [useScriptTriggerElement](/docs/api/use-script-trigger-element) to trigger scripts based on specific element interactions:

```ts
const somethingEl = ref<HTMLElement>()
const script = useScript({
src: 'https://example.com/script.js',
}, {
const buttonEl = ref<HTMLElement>()

useScript('https://example.com/feature.js', {
trigger: useScriptTriggerElement({
trigger: 'hover',
el: somethingEl,
trigger: 'visible', // or 'hover', 'click', etc.
el: buttonEl,
})
})
```

It has support for the following triggers:
- `visible` - Triggered when the element becomes visible in the viewport.
- `mouseover` - Triggered when the element is hovered over.
## Basic Triggers

## Manual Trigger
### Manual Control

The `manual` trigger allows you to manually trigger the loading of a script. This gives you complete
control over when the script is loaded.
Use `manual` trigger for complete control over script loading:

```ts
const { load } = useScript('https://example.com/script.js', {
trigger: 'manual'
})
// ...
load()

// Load when you decide
await load()
```

## Promise
### Custom Logic

You can use a promise to trigger the loading of a script. This is useful for any other custom trigger you might want to use.
Use reactive values or promises for custom loading logic:

```ts
const myScript = useScript('/script.js', {
// load after 3 seconds
trigger: new Promise(resolve => setTimeout(resolve, 3000))
::code-group

```ts [Ref]
const shouldLoad = ref(false)

useScript('https://example.com/script.js', {
trigger: shouldLoad
})

// Trigger loading
shouldLoad.value = true
```

## Ref
```ts [Computed]
const route = useRoute()

You can use a ref to trigger the loading of a script. This is useful for any other custom trigger you might want to use.
useScript('https://example.com/script.js', {
trigger: computed(() => !!route.query.affiliateId)
})
```

```ts
const myRef = ref(false)
const myScript = useScript('/script.js', {
trigger: myRef
```ts [Promise]
useScript('https://example.com/script.js', {
trigger: new Promise(resolve => setTimeout(resolve, 3000))
})
// ...
myRef.value = true
```

::
132 changes: 132 additions & 0 deletions docs/content/docs/3.api/3.use-script-trigger-idle-timeout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
---
title: useScriptTriggerIdleTimeout
description: API documentation for the useScriptTriggerIdleTimeout function.
links:
- label: Source
icon: i-simple-icons-github
to: https://github.com/nuxt/scripts/blob/main/src/runtime/composables/useScriptTriggerIdleTimeout.ts
size: xs
---

Create a trigger that loads a script after an idle timeout once Nuxt is ready. This is useful for non-critical scripts that should load with a delay to further minimize impact on initial page performance.

## Signature

```ts
function useScriptTriggerIdleTimeout(options: IdleTimeoutScriptTriggerOptions): Promise<boolean>
```

## Arguments

```ts
export interface IdleTimeoutScriptTriggerOptions {
/**
* The timeout in milliseconds to wait before loading the script.
*/
timeout: number
}
```

## Returns

A promise that resolves to `true` when the timeout completes and the script should be loaded, or `false` if the trigger is cancelled.

## Nuxt Config Usage

For convenience, you can use this trigger directly in your `nuxt.config` without calling the composable explicitly:

::code-group

```ts [Registry Script]
export default defineNuxtConfig({
scripts: {
registry: {
googleAnalytics: [{
id: 'GA_MEASUREMENT_ID'
}, {
trigger: { idleTimeout: 3000 } // Load 3 seconds after Nuxt ready
}]
}
}
})
```

```ts [Global Script]
export default defineNuxtConfig({
scripts: {
globals: {
chatWidget: ['https://widget.example.com/chat.js', {
trigger: { idleTimeout: 5000 } // Load 5 seconds after Nuxt ready
}]
}
}
})
```

::

## Examples

### Basic Usage

Load a script 5 seconds after Nuxt is ready:

```ts
const script = useScript({
src: 'https://example.com/analytics.js',
}, {
trigger: useScriptTriggerIdleTimeout({ timeout: 5000 })
})
```

### Delayed Analytics Loading

Perfect for analytics scripts that don't need to load immediately:

```vue
<script setup lang="ts">
// Load Google Analytics after a 3-second delay
const { $script } = useScriptGoogleAnalytics({
id: 'GA_MEASUREMENT_ID'
}, {
trigger: useScriptTriggerIdleTimeout({ timeout: 3000 })
})

// Track events once the script is loaded
watch($script.status, (status) => {
if (status === 'loaded') {
// Analytics is now available
gtag('event', 'page_view')
}
})
</script>
```

### Progressive Enhancement

Load enhancement scripts with a delay to prioritize critical resources:

```vue
<script setup lang="ts">
// Load chat widget after 10 seconds
const chatScript = useScript({
src: 'https://widget.intercom.io/widget/abc123'
}, {
trigger: useScriptTriggerIdleTimeout({ timeout: 10000 })
})

// Load search enhancement after 5 seconds
const searchScript = useScript({
src: 'https://cdn.example.com/search-enhancement.js'
}, {
trigger: useScriptTriggerIdleTimeout({ timeout: 5000 })
})
</script>
```

## Best Practices

- **Use appropriate timeouts**: 3-5 seconds for analytics, 5-10 seconds for widgets, longer for non-essential features
- **Consider user behavior**: Shorter timeouts for high-engagement pages, longer for content-focused pages
- **Monitor performance**: Ensure delayed loading actually improves your Core Web Vitals
- **Combine with other triggers**: Use alongside interaction triggers for optimal user experience
Loading
Loading