
3D Extruded Buildings & Urban Footprints
Real-world 3D building extrusions with dynamic sunlight shadows, terrain DEM elevations, and pitch/bearing camera controls.
tableuiPlain HTML table primitives — `<Table>`, `<TableHeader>`, `<TableRow>`, `<TableCell>` — with the registry’s borders, padding, and tokens already applied. Use this when Data Table is too heavy.
Also available for React ->$pnpm dlx shadcn-vue@latest add https://uipkge.dev/r/vue/table.json$npx shadcn-vue@latest add https://uipkge.dev/r/vue/table.json$yarn dlx shadcn-vue@latest add https://uipkge.dev/r/vue/table.json$bunx shadcn-vue@latest add https://uipkge.dev/r/vue/table.jsonnpx shadcn-vue@latest add @uipkge/tableInstalls to:app/components/ui/table/| Name | Type / Values | Default | Required |
|---|---|---|---|
class | HTMLAttributes['class'] | — | optional |
containerClasswrapper around <Table> breaks stickiness, so size the scroller here. | HTMLAttributes['class'] | — | optional |
density | 'compact''cozy''comfortable' | — | optional |
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { computed } from 'vue'
import { cn } from '@/lib/utils'
// Match DataTable's density enum so consumers can opt into the same
// runtime feel without wiring DataTable. `cozy` is the canonical default
// for bare tables (cells: py-2, head: h-10); the other two are escape
// hatches for high-density admin lists and roomy patient-facing views.
const props = defineProps<{
class?: HTMLAttributes['class']
// Extra classes for the scroll container div (e.g. `min-h-0 flex-1` inside a
// flex column). A sticky TableHeader pins to THIS div -- an outer overflow
// wrapper around <Table> breaks stickiness, so size the scroller here.
containerClass?: HTMLAttributes['class']
density?: 'compact' | 'cozy' | 'comfortable'
}>()
const densityClass = computed(() => {
if (props.density === 'compact') return '[&_td]:py-1.5 [&_td]:text-xs [&_th]:h-8 [&_th]:text-xs'
if (props.density === 'comfortable') return '[&_td]:py-3 [&_th]:h-12'
// cozy is the new TableCell/TableHead baseline (py-2 / h-10) -- no override.
return ''
})
</script>
<template>
<div data-uipkge data-slot="table-container" :class="cn('relative w-full overflow-auto', props.containerClass)">
<table data-uipkge data-slot="table" :class="cn('w-full caption-bottom text-sm', densityClass, props.class)">
<slot />
</table>
</div>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>
<template>
<tbody data-uipkge data-slot="table-body" :class="cn('[&_tr:last-child]:border-0', props.class)">
<slot />
</tbody>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>
<template>
<caption data-uipkge data-slot="table-caption" :class="cn('text-muted-foreground mt-4 text-sm', props.class)">
<slot />
</caption>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>
<template>
<td
data-uipkge
data-slot="table-cell"
:class="
cn(
'px-3 py-2 align-middle text-sm whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-0.5',
props.class,
)
"
>
<slot />
</td>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { reactiveOmit } from '@vueuse/core'
import { cn } from '@/lib/utils'
import TableCell from './TableCell.vue'
import TableRow from './TableRow.vue'
const props = withDefaults(
defineProps<{
class?: HTMLAttributes['class']
colspan?: number
}>(),
{
colspan: 1,
},
)
const delegatedProps = reactiveOmit(props, 'class')
</script>
<template>
<TableRow>
<TableCell
:class="cn('text-foreground p-4 align-middle text-sm whitespace-nowrap', props.class)"
v-bind="delegatedProps"
>
<div class="flex items-center justify-center py-10">
<slot />
</div>
</TableCell>
</TableRow>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>
<template>
<tfoot
data-uipkge
data-slot="table-footer"
:class="cn('bg-muted/50 border-t font-medium [&>tr]:last:border-b-0', props.class)"
>
<slot />
</tfoot>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>
<template>
<th
data-uipkge
data-slot="table-head"
:class="
cn(
'text-foreground h-10 px-3 text-left align-middle text-sm font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-0.5',
props.class,
)
"
>
<slot />
</th>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>
<template>
<thead data-uipkge data-slot="table-header" :class="cn('bg-muted/50 [&_tr]:border-b', props.class)">
<slot />
</thead>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>
<template>
<tr
data-uipkge
data-slot="table-row"
:class="cn('hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors duration-150', props.class)"
>
<slot />
</tr>
</template>
export { default as Table } from './Table.vue'
export { default as TableBody } from './TableBody.vue'
export { default as TableCaption } from './TableCaption.vue'
export { default as TableCell } from './TableCell.vue'
export { default as TableEmpty } from './TableEmpty.vue'
export { default as TableFooter } from './TableFooter.vue'
export { default as TableHead } from './TableHead.vue'
export { default as TableHeader } from './TableHeader.vue'
export { default as TableRow } from './TableRow.vue'
import type { Updater } from '@tanstack/vue-table'
import type { Ref } from 'vue'
import { isFunction } from '@tanstack/vue-table'
export function valueUpdater<T>(updaterOrValue: Updater<T>, ref: Ref<T>) {
ref.value = isFunction(updaterOrValue) ? updaterOrValue(ref.value) : updaterOrValue
}
Raw manifest:https://uipkge.dev/r/vue/table.json