bhylu.com

Advertisements

Vue Scoped Slots

Allow custom rendering while the child exposes a small row contract.

How it works

A scoped slot passes values from the child to the parent-provided rendering function. It is useful when a reusable list owns iteration but a caller chooses each row presentation. The slot properties are inputs for rendering, not permission to mutate child internals. Give the exposed values simple names and document which ones remain stable.

Run the code

Use a separate empty learning folder with Node 22.12+ in the 22 series. The reviewed Node version is 22.15.1. Save all files below with their exact relative paths; downloads may keep only the basename, so create src and any tests folders as listed. This project pins Vue 3.5.44 and Vite 7.3.1. Run npm install, then npm run dev and open the local address Vite prints.

Bhylu has no Vue playground. SFCs, npm imports and routing need this local project; do not paste them into the plain HTML or JavaScript editor. Apache, MySQL and changes to Bhylu server settings are not required. The application is a fictional seed-swap learning fixture.

Example

src/App.vue

<script setup>
import PacketList from "./PacketList.vue";
</script>

<template>
  <main>
    <h1>Riverside seed swap</h1>
    <PacketList v-slot="{ packet }"
      ><span>{{ packet.name }}: {{ packet.count }}</span></PacketList
    ><output data-result>Custom rows</output>
  </main>
</template>

Expected result

The parent formats a child-provided record as Beans: 3.

The child owns the array and loop. It passes one packet to each slot invocation, and the parent decides the text structure. A scoped slot does not need a separate event bus or duplicated state. If editing is allowed, design an explicit update event rather than writing through the slot object.

src/PacketList.vue

src/PacketList.vue

<script setup>
const packets = [{ id: "bean", name: "Beans", count: 3 }];
</script>
<template>
  <ul>
    <li v-for="packet in packets" :key="packet.id">
      <slot :packet="packet" />
    </li>
  </ul>
</template>

Check APIs and version differences in the official Vue guide.