use-cycle-list
Cycle through a list with wrap-around navigation.
| Package | @vizejs/composable/use-cycle-list |
| Own the source | vize lib pull composable:use-cycle-list |
| Runtime exports | useCycleList |
| Gzip budget | 768 B |
Minimal setup
Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).
vp install @vizejs/composable
Import the entry directly. Call lifecycle-bound utilities inside <script setup> so cleanup follows the component scope; consult the runtime contract for this entry's SSR and hydration behavior.
import { useCycleList } from "@vizejs/composable/use-cycle-list";
Try it
Explore component review tips
Cycle through useful review content with wrapping previous/next controls and a direct-choice selector.
What to observe: Previous tip from the first item wraps to Handle the empty state; Next tip wraps back to Name the props. Choose Label the controls directly, then continue to the next tip. The title, explanation, selector, and visible position stay synchronized.
A non-empty tuple gives state a defined item type. index is a writable computed ref; v-model.number moves the cursor through it. next() and prev() accept optional step counts, so explicit arrows keep native events out of those arguments. Navigation wraps modulo list length. Reactive list changes retain an existing current item or choose the configured fallback; the scope owns that watcher. This fixed checklist starts synchronously with its first tip during SSR and requires no browser host.
Compare the initial and interacted states


Copy the example
Save this complete SFC in your Vue project. Its public imports and source are the same ones executed in the preview.
<script setup lang="ts">
import { useId } from "vue";
import { useCycleList } from "@vizejs/composable/use-cycle-list";
const tipId = useId();
const {
state: tip,
index,
list,
next,
prev,
} = useCycleList([
{ title: "Name the props", text: "Use clear prop names and document the values they accept." },
{
title: "Label the controls",
text: "Give each form control a label that explains its purpose.",
},
{ title: "Handle the empty state", text: "Explain what users can do when a list has no items." },
] as const);
</script>
<template>
<div class="composable-example">
<p>Explore a short component review checklist. Previous and Next wrap around the list.</p>
<label :for="tipId">Review tip</label>
<select :id="tipId" v-model.number="index">
<option v-for="(item, position) in list" :key="item.title" :value="position">
{{ item.title }}
</option>
</select>
<output aria-live="polite">Tip {{ index + 1 }} of {{ list.length }}: {{ tip.title }}</output>
<h3>{{ tip.title }}</h3>
<p>{{ tip.text }}</p>
<div class="example-actions">
<button type="button" @click="() => prev()">Previous tip</button>
<button type="button" @click="() => next()">Next tip</button>
</div>
<p>You can also choose a tip directly. Navigation continues from that choice.</p>
</div>
</template>
Runtime contract
| Utility | Category | Stability | SSR | Hydration | Cleanup | Targets | Host globals | Uses |
|---|---|---|---|---|---|---|---|---|
useCycleList |
state | experimental | safe | stable | reactive-scope | web, server, worker, native, desktop, terminal | — | — |
API
useCycleList
Cycle through a list with wrap-around navigation. Non-empty tuple sources (["light", "dark", "system"] as const) yield a state typed as the element union; general arrays may be empty, so their state includes undefined. When the list changes, the cursor keeps the current item if it is still present and otherwise moves to fallbackIndex. Synchronous state: SSR-safe; the list watcher follows the owning scope.
function useCycleList<const List extends readonly [unknown, ...unknown[]]>( list: MaybeRefOrGetter<List>, options?: UseCycleListOptions<List[number]>, ): CycleList<List[number], List[number]>
const { state, next } = useCycleList(["light", "dark", "system"] as const);
next(); // "dark"
useCycleList
function useCycleList<Item>( list: MaybeRefOrGetter<readonly Item[]>, options?: UseCycleListOptions<Item>, ): CycleList<Item | undefined, Item>
useCycleList
function useCycleList<Item>( list: MaybeRefOrGetter<readonly Item[]>, options: UseCycleListOptions<Item> = {}, ): CycleList<Item | undefined, Item>
Types
UseCycleListOptions
Options for useCycleList.
| Member | Type | Description |
|---|---|---|
initialValue? |
Item |
Item selected initially. |
fallbackIndex? |
number |
Index used when the current item is not in the list. |
getIndexOf? |
(item: Item, list: readonly Item[]) => number |
Locate an item in the list, for example by id. |
CycleList
Cursor over a list returned by useCycleList.
| Member | Type | Description |
|---|---|---|
state |
ShallowRef<Current> |
Current item. Writable: assigning moves the cursor to that item. |
index |
WritableComputedRef<number> |
Current index. Writable: assigning wraps around the list. |
next |
(steps?: number) => Current |
Move forward steps items (default 1), wrapping around. |
prev |
(steps?: number) => Current |
Move backward steps items (default 1), wrapping around. |
go |
(index: number) => Current |
Jump to index, wrapping around. |
list |
Readonly<ShallowRef<readonly Item[]>> |
The list items, for convenience. |