Вот так:
import { useSlots, computed } from 'vue';
const slots = useSlots();
const columns = computed(() => slots.default?.().filter(n => n.props));
<table>
<thead>
<tr>
<th v-for="{ props: p, children: c } in columns" :key="p.prop">
<component v-if="c?.header" :is="c.header" />
<template v-else>{{ p.label }}</template>
</th>
</tr>
</thead>
<tbody>
<tr v-for="row in data">
<td v-for="{ props: p, children: c } in columns" :key="p.prop">
<component v-if="c?.body" :is="c.body" :row="row" />
<template v-else>{{ row[p.prop] }}</template>
</td>
</tr>
</tbody>
</table>