Vize

use-sorted

Sorted copy of a reactive array; the source is never mutated.

Package @vizejs/composable/use-sorted
Own the source vize lib pull composable:use-sorted
Runtime exports useSorted
Gzip budget 512 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 { useSorted } from "@vizejs/composable/use-sorted";

Try it

Rank scores on a leaderboard

Show a sorted view of a list while keeping the original order intact.

Open the interactive example

What to observe: The leaderboard starts 95, 72, 64. Add 80 and it appears second, while Entered order keeps the order the scores were added.

useSorted returns a computed copy; the source array is never sorted in place. The comparator works like Array.prototype.sort.

Compare the initial and interacted states
Rank scores on a leaderboard: initial state
Initial state
Rank scores on a leaderboard: state after the verified interactions
After the verified interactions

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 { ref } from "vue";
import { useSorted } from "@vizejs/composable/use-sorted";

const scores = ref([
  { id: 1, value: 72 },
  { id: 2, value: 95 },
  { id: 3, value: 64 },
]);
const ranking = useSorted(scores, (left, right) => right.value - left.value);
const score = ref(80);
let nextId = 4;

function addScore() {
  scores.value = [...scores.value, { id: nextId, value: score.value }];
  nextId += 1;
}
</script>

<template>
  <div class="composable-example">
    <p>Show a leaderboard from scores entered in any order.</p>
    <label>
      New score
      <input v-model.number="score" type="number" min="0" max="100" />
    </label>
    <button type="button" @click="addScore">Add score</button>
    <ol aria-label="Leaderboard">
      <li v-for="entry in ranking" :key="entry.id">{{ entry.value }}</li>
    </ol>
    <output aria-live="polite"
      >Entered order: {{ scores.map((entry) => entry.value).join(", ") }}</output
    >
  </div>
</template>

Runtime contract

Utility Category Stability SSR Hydration Cleanup Targets Host globals Uses
useSorted state experimental safe stable none web, server, worker, native, desktop, terminal — —

API

useSorted

Sorted copy of a reactive array; the source is never mutated. Numbers, bigints, strings, and dates sort in natural ascending order by default (numerically, unlike Array.prototype.sort); any other item type requires a comparator. The sort is stable. Pure derived state: SSR-safe and nothing to dispose.

function useSorted<Item extends NaturallyOrdered>( source: MaybeRefOrGetter<readonly Item[]>, compare?: SortComparator<Item>, ): ComputedRef<Item[]>
const ranked = useSorted(players, (a, b) => b.score - a.score);
const ascending = useSorted([10, 9, 100]); // [9, 10, 100]

useSorted

function useSorted<Item>( source: MaybeRefOrGetter<readonly Item[]>, compare: SortComparator<Item>, ): ComputedRef<Item[]>

useSorted

function useSorted( source: MaybeRefOrGetter<readonly NaturallyOrdered[]>, compare: SortComparator<NaturallyOrdered> = naturalOrder, ): ComputedRef<NaturallyOrdered[]>