Components

Small building blocks. Everything else you see in this playground ( Button , Card , Badge , Avatar …) is Nuxt UI , registered without the U prefix.

Source in the kit: components/Loader.vue · Empty.vue · Image.vue · Log/

Loader and Empty

examples/components/LoaderEmpty.vue
<template>
  <div class="space-y-4">
    <div class="flex gap-2">
      <Button
        label="Loading"
        size="sm"
        :variant="state === 'loading' ? 'solid' : 'outline'"
        @click="state = 'loading'"
      />
      <Button
        label="Empty"
        size="sm"
        :variant="state === 'empty' ? 'solid' : 'outline'"
        @click="state = 'empty'"
      />
      <Button
        label="Data"
        size="sm"
        :variant="state === 'data' ? 'solid' : 'outline'"
        @click="state = 'data'"
      />
    </div>

    <div class="min-h-40 rounded-lg border border-gray-200 p-4">
      <!-- Loader shows a spinner while `loading`, then its default slot -->
      <Loader :loading="state === 'loading'">
        <!-- Empty's text comes from core.messages.common.empty; `message` and `icon` override it -->
        <Empty
          v-if="state === 'empty'"
          message="No invoices yet"
          icon="ph:receipt"
        />
        <p v-else>3 invoices</p>
      </Loader>
    </div>
  </div>
</template>

<script lang="ts" setup>
const state = ref<'loading' | 'empty' | 'data'>('loading')
</script>

Image

examples/components/ImageStates.vue
Loads: spinner first, then the picture
Fails: error icon instead of a broken image
#error and #loading slots replace the defaults
<template>
  <div class="grid grid-cols-2 gap-4 md:grid-cols-3">
    <figure>
      <Image
        src="https://placehold.co/320x200/png"
        class="h-32 w-full rounded-lg object-cover"
      />
      <figcaption class="mt-1 text-xs text-gray-500">Loads: spinner first, then the picture</figcaption>
    </figure>

    <figure>
      <div class="h-32 w-full rounded-lg bg-gray-50">
        <Image src="https://example.invalid/missing.png" />
      </div>
      <figcaption class="mt-1 text-xs text-gray-500">Fails: error icon instead of a broken image</figcaption>
    </figure>

    <figure>
      <div class="h-32 w-full rounded-lg bg-gray-50">
        <Image src="https://example.invalid/missing.png">
          <template #error>
            <div class="flex h-full items-center justify-center text-sm text-gray-400">No photo</div>
          </template>
        </Image>
      </div>
      <figcaption class="mt-1 text-xs text-gray-500">#error and #loading slots replace the defaults</figcaption>
    </figure>
  </div>
</template>

Log: inspect values while developing

examples/components/LogDebug.vue

Type above, then open the floating DevTools panel in the corner. Log is wrapped in DevOnly , so it is safe to leave in a page: production renders nothing.

<template>
  <div class="space-y-3">
    <FormFields :options="fields" />

    <!-- Renders nothing here: in development the values appear in the DevTools window (bottom right) -->
    <Log
      title="Example form"
      :data="form.values"
    />

    <p class="text-sm text-gray-500">
      Type above, then open the floating DevTools panel in the corner.
      <code>Log</code>
      is wrapped in
      <code>DevOnly</code>
      , so it is safe to leave in a page: production renders nothing.
    </p>
  </div>
</template>

<script lang="ts" setup>
const form = useForm({
  initialValues: {
    note: '',
  },
})

const fields = createFormFields(() => [
  {
    type: INPUT_TYPES.TEXT,
    props: {
      name: 'note',
      label: 'Note',
    },
  },
])
</script>