Skip to content

Commit 6fbeb69

Browse files
authored
feat: new event triggers (#515)
1 parent b98c236 commit 6fbeb69

File tree

8 files changed

+682
-93
lines changed

8 files changed

+682
-93
lines changed
Lines changed: 90 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,56 @@
11
---
2-
title: Triggering Script Loading
2+
title: Script Triggers
3+
description: Control when scripts load with Nuxt Scripts' flexible trigger system.
34
---
45

5-
Nuxt Scripts provides several ways to trigger the loading of scripts.
6+
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.
67

7-
::code-group
8+
## Default: onNuxtReady
89

9-
```ts [useScript - Ref]
10-
import { useTimeout } from '@vueuse/core'
10+
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.
1111

12-
const { ready } = useTimeout(3000)
13-
useScript({
14-
src: 'https://example.com/script.js',
15-
}, {
16-
// load however you like!
17-
trigger: ready, // refs supported
12+
The `onNuxtReady` trigger ensures scripts load:
13+
- After Nuxt hydration is complete
14+
- When the browser is idle and the main thread is available
15+
- Without blocking critical page rendering or user interactions
16+
17+
```ts
18+
// Default behavior - explicit for clarity
19+
useScript('https://widget.intercom.io/widget/abc123', {
20+
trigger: 'onNuxtReady'
1821
})
19-
```
2022

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

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

34-
const { ready } = useTimeout(3000)
35-
useScriptMetaPixel({
36-
id: '1234567890',
37-
scriptOptions: {
38-
trigger: ready
39-
}
32+
## Specialized Triggers
33+
34+
### Idle Timeout
35+
36+
Use [useScriptTriggerIdleTimeout](/docs/api/use-script-trigger-idle-timeout) to delay script loading for a specified time after Nuxt is ready:
37+
38+
::code-group
39+
40+
```ts [Composable]
41+
useScript('https://example.com/analytics.js', {
42+
trigger: useScriptTriggerIdleTimeout({ timeout: 5000 })
4043
})
4144
```
4245

43-
```ts [Global Script]
46+
```ts [nuxt.config.ts]
4447
export default defineNuxtConfig({
4548
scripts: {
46-
globals: {
47-
myScript: ['https://example.com/script.js', {
48-
// load after page is fully interactive (idle loading)
49-
trigger: 'onNuxtReady'
49+
registry: {
50+
googleAnalytics: [{
51+
id: 'GA_MEASUREMENT_ID'
52+
}, {
53+
trigger: { idleTimeout: 3000 }
5054
}]
5155
}
5256
}
@@ -55,93 +59,93 @@ export default defineNuxtConfig({
5559

5660
::
5761

58-
## Default Behavior
59-
60-
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.
61-
62-
The `onNuxtReady` trigger ensures scripts load:
63-
- After Nuxt hydration is complete
64-
- When the browser is idle and the main thread is available
65-
- Without blocking critical page rendering or user interactions
66-
67-
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.
68-
69-
You can change this default by modifying the [defaultScriptOptions](/docs/api/nuxt-config#defaultscriptoptions).
62+
### User Interaction
7063

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

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

75-
```ts
76-
// Chat widget - loads after page is fully interactive
77-
useScript('https://widget.intercom.io/widget/abc123', {
78-
trigger: 'onNuxtReady' // default behavior
68+
```ts [Composable]
69+
useScript('https://example.com/chat-widget.js', {
70+
trigger: useScriptTriggerInteraction({
71+
events: ['scroll', 'click', 'keydown']
72+
})
7973
})
74+
```
8075

81-
// Explicitly using onNuxtReady for clarity
82-
useScriptGoogleAnalytics({
83-
id: 'GA_MEASUREMENT_ID',
84-
scriptOptions: {
85-
trigger: 'onNuxtReady'
76+
```ts [nuxt.config.ts]
77+
export default defineNuxtConfig({
78+
scripts: {
79+
globals: {
80+
chatWidget: ['https://widget.example.com/chat.js', {
81+
trigger: { interaction: ['scroll', 'click', 'touchstart'] }
82+
}]
83+
}
8684
}
8785
})
8886
```
8987

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

92-
## Element Event Triggers
90+
### Element Events
9391

94-
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.
92+
Use [useScriptTriggerElement](/docs/api/use-script-trigger-element) to trigger scripts based on specific element interactions:
9593

9694
```ts
97-
const somethingEl = ref<HTMLElement>()
98-
const script = useScript({
99-
src: 'https://example.com/script.js',
100-
}, {
95+
const buttonEl = ref<HTMLElement>()
96+
97+
useScript('https://example.com/feature.js', {
10198
trigger: useScriptTriggerElement({
102-
trigger: 'hover',
103-
el: somethingEl,
99+
trigger: 'visible', // or 'hover', 'click', etc.
100+
el: buttonEl,
104101
})
105102
})
106103
```
107104

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

112-
## Manual Trigger
107+
### Manual Control
113108

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

117111
```ts
118112
const { load } = useScript('https://example.com/script.js', {
119113
trigger: 'manual'
120114
})
121-
// ...
122-
load()
115+
116+
// Load when you decide
117+
await load()
123118
```
124119

125-
## Promise
120+
### Custom Logic
126121

127-
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.
122+
Use reactive values or promises for custom loading logic:
128123

129-
```ts
130-
const myScript = useScript('/script.js', {
131-
// load after 3 seconds
132-
trigger: new Promise(resolve => setTimeout(resolve, 3000))
124+
::code-group
125+
126+
```ts [Ref]
127+
const shouldLoad = ref(false)
128+
129+
useScript('https://example.com/script.js', {
130+
trigger: shouldLoad
133131
})
132+
133+
// Trigger loading
134+
shouldLoad.value = true
134135
```
135136

136-
## Ref
137+
```ts [Computed]
138+
const route = useRoute()
137139

138-
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.
140+
useScript('https://example.com/script.js', {
141+
trigger: computed(() => !!route.query.affiliateId)
142+
})
143+
```
139144

140-
```ts
141-
const myRef = ref(false)
142-
const myScript = useScript('/script.js', {
143-
trigger: myRef
145+
```ts [Promise]
146+
useScript('https://example.com/script.js', {
147+
trigger: new Promise(resolve => setTimeout(resolve, 3000))
144148
})
145-
// ...
146-
myRef.value = true
147149
```
150+
151+
::
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
---
2+
title: useScriptTriggerIdleTimeout
3+
description: API documentation for the useScriptTriggerIdleTimeout function.
4+
links:
5+
- label: Source
6+
icon: i-simple-icons-github
7+
to: https://github.com/nuxt/scripts/blob/main/src/runtime/composables/useScriptTriggerIdleTimeout.ts
8+
size: xs
9+
---
10+
11+
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.
12+
13+
## Signature
14+
15+
```ts
16+
function useScriptTriggerIdleTimeout(options: IdleTimeoutScriptTriggerOptions): Promise<boolean>
17+
```
18+
19+
## Arguments
20+
21+
```ts
22+
export interface IdleTimeoutScriptTriggerOptions {
23+
/**
24+
* The timeout in milliseconds to wait before loading the script.
25+
*/
26+
timeout: number
27+
}
28+
```
29+
30+
## Returns
31+
32+
A promise that resolves to `true` when the timeout completes and the script should be loaded, or `false` if the trigger is cancelled.
33+
34+
## Nuxt Config Usage
35+
36+
For convenience, you can use this trigger directly in your `nuxt.config` without calling the composable explicitly:
37+
38+
::code-group
39+
40+
```ts [Registry Script]
41+
export default defineNuxtConfig({
42+
scripts: {
43+
registry: {
44+
googleAnalytics: [{
45+
id: 'GA_MEASUREMENT_ID'
46+
}, {
47+
trigger: { idleTimeout: 3000 } // Load 3 seconds after Nuxt ready
48+
}]
49+
}
50+
}
51+
})
52+
```
53+
54+
```ts [Global Script]
55+
export default defineNuxtConfig({
56+
scripts: {
57+
globals: {
58+
chatWidget: ['https://widget.example.com/chat.js', {
59+
trigger: { idleTimeout: 5000 } // Load 5 seconds after Nuxt ready
60+
}]
61+
}
62+
}
63+
})
64+
```
65+
66+
::
67+
68+
## Examples
69+
70+
### Basic Usage
71+
72+
Load a script 5 seconds after Nuxt is ready:
73+
74+
```ts
75+
const script = useScript({
76+
src: 'https://example.com/analytics.js',
77+
}, {
78+
trigger: useScriptTriggerIdleTimeout({ timeout: 5000 })
79+
})
80+
```
81+
82+
### Delayed Analytics Loading
83+
84+
Perfect for analytics scripts that don't need to load immediately:
85+
86+
```vue
87+
<script setup lang="ts">
88+
// Load Google Analytics after a 3-second delay
89+
const { $script } = useScriptGoogleAnalytics({
90+
id: 'GA_MEASUREMENT_ID'
91+
}, {
92+
trigger: useScriptTriggerIdleTimeout({ timeout: 3000 })
93+
})
94+
95+
// Track events once the script is loaded
96+
watch($script.status, (status) => {
97+
if (status === 'loaded') {
98+
// Analytics is now available
99+
gtag('event', 'page_view')
100+
}
101+
})
102+
</script>
103+
```
104+
105+
### Progressive Enhancement
106+
107+
Load enhancement scripts with a delay to prioritize critical resources:
108+
109+
```vue
110+
<script setup lang="ts">
111+
// Load chat widget after 10 seconds
112+
const chatScript = useScript({
113+
src: 'https://widget.intercom.io/widget/abc123'
114+
}, {
115+
trigger: useScriptTriggerIdleTimeout({ timeout: 10000 })
116+
})
117+
118+
// Load search enhancement after 5 seconds
119+
const searchScript = useScript({
120+
src: 'https://cdn.example.com/search-enhancement.js'
121+
}, {
122+
trigger: useScriptTriggerIdleTimeout({ timeout: 5000 })
123+
})
124+
</script>
125+
```
126+
127+
## Best Practices
128+
129+
- **Use appropriate timeouts**: 3-5 seconds for analytics, 5-10 seconds for widgets, longer for non-essential features
130+
- **Consider user behavior**: Shorter timeouts for high-engagement pages, longer for content-focused pages
131+
- **Monitor performance**: Ensure delayed loading actually improves your Core Web Vitals
132+
- **Combine with other triggers**: Use alongside interaction triggers for optimal user experience

0 commit comments

Comments
 (0)