Atom
Renders any HTML element or outputs nothing at all—your choice.
Usage
Use Atom when you need to:
Render the same component as different elements (e.g.,
<button>vs<a>)Output slot content without a wrapper element (renderless mode)
Build higher-level components that inherit polymorphic behavior
The as prop accepts any HTML tag name. Set as to null or use the renderless prop to skip the wrapper entirely and render only slot content.
Inspect the DOM to verify the element type.
<script setup lang="ts">
import { Atom } from '@vuetify/v0'
import { ref } from 'vue'
const element = ref<'button' | 'a' | 'div' | null>('button')
const options = ['button', 'a', 'div', null] as const
</script>
<template>
<div class="space-y-4">
<div class="flex gap-2">
<button
v-for="opt in options"
:key="String(opt)"
class="px-3 py-1 border rounded text-sm"
:class="element === opt ? 'bg-primary text-on-primary' : 'bg-surface'"
@click="element = opt"
>
{{ opt ?? 'null' }}
</button>
</div>
<div class="p-4 border border-dashed rounded min-h-16 flex items-center">
<Atom
:as="element"
class="px-4 py-2 border border-primary rounded bg-surface-tint"
:href="element === 'a' ? '#' : undefined"
>
<template v-if="element">
I'm a <{{ element }}>
</template>
<template v-else>
<span class="text-secondary">No wrapper—just this span</span>
</template>
</Atom>
</div>
<p class="text-sm text-secondary">
<template v-if="element === null">
Renderless mode: slot content renders without a wrapper element.
</template>
<template v-else-if="element === 'a'">
Links get href. Inspect the DOM to verify the element type.
</template>
<template v-else>
Inspect the DOM to verify the element type.
</template>
</p>
</div>
</template>
Anatomy
Anatomy
<script setup lang="ts">
import { Atom } from '@vuetify/v0'
</script>
<template>
<Atom />
</template>In Practice
All v0 components use Atom internally with sensible defaults:
| Component | Default as | Why |
|---|---|---|
PaginationItem | button | Interactive by default |
AvatarRoot | div | Container element |
DialogRoot | null | Pure context provider, no DOM |
vue
<script setup lang="ts">
// Inside PaginationItem.vue
import { Atom } from '@vuetify/v0'
const { as = 'button', renderless, value } = defineProps<PaginationItemProps>()
const slotProps = computed(() => ({
page: value,
isSelected: isSelected.value,
select,
attrs: {
'aria-label': `Go to page ${value}`,
'aria-current': isSelected.value ? 'page' : undefined,
onClick: select,
},
}))
</script>
<template>
<!-- Renders as <button> by default, but consumers can override -->
<Atom :as :renderless v-bind="slotProps.attrs">
<slot v-bind="slotProps">
{{ value }}
</slot>
</Atom>
</template>Each component exposes the as and renderless props, so you can override the default when needed.
Was this page helpful?