Skip to main content
Not yet stable
@foresightjs/vue is at 0.1.0 and not yet stable. It works and is fully tested, but the API may still change.
Version: 4.0

Foresight component

Foresight is the component form of useForesight: one instance, one registration. It renders in one of two ways.

Rendering an element with as

With as, Foresight renders that element itself and registers it.

<script setup lang="ts">
import { Foresight } from "@foresightjs/vue"
</script>

<template>
<Foresight as="button" :callback="() => prefetch('/checkout')" @click="checkout">
Checkout
</Foresight>
</template>

as accepts any element tag ("button", "a", "div", ...) or a component whose root is a DOM element.

note

In the as form there is no way to pass your own ref to the rendered element, Foresight uses the ref slot for its registration. If you need the DOM node, use the render-prop form below and attach both refs yourself.

Styling with data attributes

In the as form, Foresight mirrors the element state onto data attributes — by mutating the DOM directly, without re-rendering the component:

  • data-predicted — present while isPredicted is true
  • data-callback-running — present while the callback is executing
  • data-status"success" or "error" after the last callback run

This makes prediction styling pure CSS:

button[data-predicted] {
outline: 1px solid orange;
}

Or with Tailwind:

<Foresight as="button" :callback="() => prefetch('/checkout')" class="data-predicted:outline-1">
Checkout
</Foresight>

Reading state in as form

To use the reactive state in this form, read it from the scoped default slot:

<Foresight as="button" :callback="() => prefetch('/checkout')" #default="{ isCallbackRunning }">
{{ isCallbackRunning ? "Prefetching…" : "Checkout" }}
</Foresight>

Render-prop form

Without as, Foresight renders only its default slot. The scoped slot receives the reactive state plus the elementRef to attach, which gives full control over the markup:

<script setup lang="ts">
import { Foresight } from "@foresightjs/vue"
</script>

<template>
<Foresight
foresight-name="checkout"
:callback="() => prefetch('/checkout')"
#default="{ elementRef, isPredicted }"
>
<button :ref="elementRef" :class="{ predicted: isPredicted }">Checkout</button>
</Foresight>
</template>

You must bind elementRef to an element with :ref="elementRef", without it nothing is registered with Foresight.

Options

Foresight takes the same options as useForesight, passed as props. The only renamed option is name, on the component it is foresightName, so the HTML name attribute (on input, button, select, ...) falls through to the element like any other attribute.

Dynamic lists

Foresight can be rendered in a v-for, registering one element per item:

<script setup lang="ts">
import { Foresight } from "@foresightjs/vue"

const links = [
{ href: "/about", label: "About" },
{ href: "/contact", label: "Contact" },
]
</script>

<template>
<nav>
<Foresight
v-for="link in links"
:key="link.href"
as="a"
:href="link.href"
:foresight-name="link.label"
:callback="() => prefetch(link.href)"
>
{{ link.label }}
</Foresight>
</nav>
</template>