Skip to main content
You are viewing Pre-Alpha documentation.
Vuetify0 Logo
Theme
Mode
Accessibility
Vuetify

Atom

Renders any HTML element or outputs nothing at all—your choice.


Renders elementIntermediate100% coverageJan 27, 2026

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 &lt;{{ element }}&gt;
        </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:

ComponentDefault asWhy
PaginationItembuttonInteractive by default
AvatarRootdivContainer element
DialogRootnullPure 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.

API Reference

The following API details are for all variations of the Atom component.

Atom

Props

as

any

The HTML element to render as, or null for renderless mode

Default: "div"

renderless

boolean

When true, renders slot content directly without a wrapper element

Default: false

Slots

default

T

Default slot that receives all forwarded attributes as props

Was this page helpful?

© 2016-1970 Vuetify, LLC
Ctrl+/