Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/7span/vue-list/llms.txt

Use this file to discover all available pages before exploring further.

Overview

VueList is a headless component library that handles the data layer of your lists while giving you complete control over the UI. It manages pagination, filtering, sorting, search, and API calls — you focus on rendering.

Quick Setup

1

Install VueList

First, install the package in your Vue 3 project:
npm install @7span/vue-list
2

Configure the Plugin

Set up VueList globally with a requestHandler function. This function tells VueList how to fetch data from your API.
main.js
import { createApp } from 'vue'
import VueList from '@7span/vue-list'
import axios from 'axios'
import App from './App.vue'

const app = createApp(App)

app.use(VueList, {
  requestHandler(context) {
    const { endpoint, page, perPage, search, filters, sortBy, sortOrder } = context

    return axios
      .get(`/api/${endpoint}`, {
        params: {
          page,
          limit: perPage,
          search,
          sort_by: sortBy,
          sort_order: sortOrder,
          ...filters
        }
      })
      .then(({ data }) => {
        return {
          items: data.results,  // Array of items to display
          count: data.total     // Total number of items available
        }
      })
  }
})

app.mount('#app')
The requestHandler must return a Promise that resolves with an object containing:
  • items: Array of data to display
  • count: Total number of items (for pagination)
3

Create Your First List

Now you can use VueList components anywhere in your app:
users.vue
<template>
  <VueList endpoint="users" :per-page="10">
    <VueListInitialLoader />
    <VueListError />
    
    <VueListItems>
      <template #item="{ item }">
        <div class="user-card">
          <h3>{{ item.name }}</h3>
          <p>{{ item.email }}</p>
        </div>
      </template>
    </VueListItems>
    
    <VueListPagination />
  </VueList>
</template>

Core Components

VueList provides several components that work together:

VueList (Root)

The root component that manages all state and provides context to child components.
<VueList 
  endpoint="products" 
  :per-page="25"
  :page="1"
  pagination-mode="pagination"
>
  <!-- Child components go here -->
</VueList>
Key Props:
  • endpoint (required) - Identifier passed to your requestHandler
  • per-page - Number of items per page (default: 25)
  • page - Initial page number (default: 1)
  • pagination-mode - Either "pagination" or "loadMore"

VueListItems

Renders the list items. Automatically hidden during initial load.
<VueListItems>
  <template #item="{ item, index }">
    <div class="product">
      <span>{{ index + 1 }}. {{ item.name }}</span>
      <span>${{ item.price }}</span>
    </div>
  </template>
</VueListItems>

VueListInitialLoader

Shows a loading state only on the first data fetch.
<VueListInitialLoader>
  <div class="spinner">Loading...</div>
</VueListInitialLoader>

VueListError

Displays errors from failed API requests.
<VueListError v-slot="{ error }">
  <div class="error-message">
    <p>{{ error.message }}</p>
  </div>
</VueListError>

VueListEmpty

Shows when the list has no items (and is not loading or in error state).
<VueListEmpty>
  <p>No users found.</p>
</VueListEmpty>

Complete Example

Here’s a fully working example with all the essential components:
products.vue
<template>
  <div class="products-page">
    <VueList 
      endpoint="products" 
      :per-page="12"
      pagination-mode="pagination"
    >
      <div class="products-header">
        <h1>Products</h1>
        <VueListSummary v-slot="{ from, to, count }">
          <span>Showing {{ from }}-{{ to }} of {{ count }} products</span>
        </VueListSummary>
      </div>

      <!-- Loading state on first load -->
      <VueListInitialLoader>
        <div class="loading-spinner">
          <p>Loading products...</p>
        </div>
      </VueListInitialLoader>

      <!-- Error state -->
      <VueListError v-slot="{ error }">
        <div class="error-banner">
          <p>Failed to load products: {{ error.message }}</p>
        </div>
      </VueListError>

      <!-- The actual list -->
      <VueListItems>
        <template #default="{ items }">
          <div class="products-grid">
            <div 
              v-for="product in items" 
              :key="product.id" 
              class="product-card"
            >
              <img :src="product.image" :alt="product.name" />
              <h3>{{ product.name }}</h3>
              <p class="price">${{ product.price }}</p>
              <button>Add to Cart</button>
            </div>
          </div>
        </template>
      </VueListItems>

      <!-- Empty state -->
      <VueListEmpty>
        <div class="empty-state">
          <p>No products found</p>
        </div>
      </VueListEmpty>

      <!-- Pagination -->
      <VueListPagination />
    </VueList>
  </div>
</template>

<style scoped>
.products-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 1.5rem;
}

.product-card {
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  padding: 1rem;
}

.loading-spinner,
.error-banner,
.empty-state {
  padding: 2rem;
  text-align: center;
}
</style>

Accessing List State

You can access the full list state using the default slot on <VueList>:
<VueList endpoint="users" v-slot="{ items, count, isLoading, error, refresh }">
  <div>
    <button @click="refresh()" :disabled="isLoading">
      Refresh List
    </button>
    
    <p v-if="isLoading">Loading...</p>
    <p v-else>Total: {{ count }} users</p>
    
    <div v-for="user in items" :key="user.id">
      {{ user.name }}
    </div>
  </div>
</VueList>
Available slot props:
  • items - Array of current page items
  • count - Total number of items
  • isLoading - Whether data is being fetched
  • isInitialLoading - Whether this is the first load
  • error - Error object if request failed
  • isEmpty - Whether items array is empty
  • response - Full API response object
  • refresh() - Function to manually refetch data
Most of the time you won’t need to use the scoped slot on <VueList> directly. The child components like <VueListItems>, <VueListError>, etc. automatically access the state they need through Vue’s provide/inject.

Next Steps

Pagination Modes

Learn about pagination vs load-more modes

Filtering & Sorting

Add filters and sorting to your lists

State Persistence

Persist list state across page refreshes

Custom Styling

Style components with slots and custom markup