Getting started

Installation

Documentation for veload@0.1.2. Install Veload from npm, then import its Vue components and stylesheet in your application.

Requirements

  • Vue ^3.5.2 as a peer dependency: Vue 3.5.2 or a later compatible Vue 3 release, not Vue 4. The declarations use Vue 3.5 types; Vue 3.0–3.4 are outside the supported peer range.
  • A Vue application build tool, such as Vite with its Vue plugin or Nuxt. The package ships compiled JavaScript and TypeScript declarations; consumers do not compile its source SFCs.
  • A browser with CSS custom properties, color-mix() and :has() for the full loader collection.

Install the package

Install the published MIT-licensed package using your preferred package manager. The documentation version follows the library source, not necessarily the currently published npm release. The playground's local monorepo dependency is only for maintaining this site; consumers do not need a repository clone, local build or link step.

bash
npm install veload

Register the stylesheet

Component styles are extracted into a single veload/style.css file. Import it once, globally. The JavaScript entry point does not inject styles automatically, so without this import the components render without their intended appearance and animations.

Nuxt
ts
// nuxt.config.ts
export default defineNuxtConfig({
  css: ["veload/style.css"],
});

Vite
ts
// main.ts
import { createApp } from "vue";
import "veload/style.css";
import App from "./App.vue";

createApp(App).mount("#app");

Import the components

Every component and composable is a named export from veload. The root entry provides ESM, CommonJS and dist/index.d.ts declarations. Use the public package entry rather than importing private source or dist paths. There is no default plugin, Nuxt module or global loading manager. Import only what you use so the bundler can drop unused JavaScript; the stylesheet still includes every component.

Imports
ts
import {
  VLoading,
  VLoadingButton,
  VLoader,
  VProgress,
  VSkeleton,
  VSkeletonSwitch,
  VSpinner,
  useDelayedLoading,
  useLoading,
  useLoadingGroup,
} from "veload";

First use

In a Vue single-file component, <script setup> imports are available directly in the template; no registration step is needed. This example starts a request only on a button click and handles errors in the application. Supply your own /api/message endpoint returning a JSON string; the library does not provide it or perform requests automatically.

Example.vue
vue
<script setup lang="ts">
import { ref } from "vue";
import { VLoading, useLoading } from "veload";
import "veload/style.css";

const { isLoading, execute } = useLoading();
const message = ref<string | null>(null);

async function load() {
  try {
    message.value = await execute(async () => {
      const response = await fetch("/api/message");
      if (!response.ok) throw new Error("Request failed");
      return (await response.json()) as string;
    });
  } catch (error) {
    message.value = error instanceof Error ? error.message : "Unknown error";
  }
}
</script>

<template>
  <VLoading :loading="isLoading" label="Loading message">
    <button type="button" @click="load">Reload</button>
    <p v-if="message">{{ message }}</p>
  </VLoading>
</template>

Optional registration

Prefer SFC imports. In an Options API component, use components: { VSpinner } after importing it. If your app intentionally uses global components, register individual named exports with Vue's app.component(), not app.use(Veload):

main.ts · optional
ts
// main.ts (optional, instead of importing in each component)
import { createApp } from "vue";
import { VSpinner } from "veload";
import "veload/style.css";
import App from "./App.vue";

const app = createApp(App);
app.component("VSpinner", VSpinner);
app.mount("#app");

Runtime global registration does not add template types automatically. Prefer local imports for type inference, or declare Vue's GlobalComponents types in your app when using global components with a template type checker.

TypeScript

Prop types, loader variants and composable return types are exported from the package root. Declarations are included through the types export; no separate types package or shim is needed. Use import type for type-only imports and a Vue-aware checker such as vue-tsc (or Nuxt's nuxt typecheck) to check SFC templates.

Types
ts
import type {
  LoaderVariant,
  NamedLoaderProps,
  VLoadingProps,
  VProgressProps,
  VSkeletonProps,
  VSpinnerProps,
  UseLoadingReturn,
} from "veload";

Nuxt and server rendering

Register veload/style.css in the Nuxt css option above, then import components directly in page or component SFCs. The library can render on the server; no client-only plugin or ClientOnly wrapper is required.

For initial server-fetched data, use Nuxt's useFetch or useAsyncData so its payload is reused during hydration instead of issuing a second request. This example uses the same application-owned endpoint:

pages/message.vue · Nuxt
vue
<script setup lang="ts">
import { VLoading } from "veload";

const { data: message, status, error, refresh } =
  await useFetch<string>("/api/message");
</script>

<template>
  <VLoading :loading="status === 'pending'" label="Loading message">
    <button type="button" @click="refresh()">Reload</button>
    <p v-if="error">Could not load the message.</p>
    <p v-else-if="message">{{ message }}</p>
  </VLoading>
</template>

Create useLoading() and useDelayedLoading() inside component setup, not at module scope where mutable state could be shared between SSR requests. Use them for user-triggered work; they track activity, not Nuxt data fetching or payload serialization. Keep browser-only work in event handlers or onMounted, and use the same initial loading state on the server and client to avoid hydration mismatches.