🟒 Badge


Basic

NBadge is a component that can be used to display a small badge with a number or text.

You can use label prop or default slot to set the label text.

Badge 4
<template>
  <div flex gap-4>
    <NBadge label="Badge" />

    <NBadge class="rounded-full">
      4
    </NBadge>
  </div>
</template>

Variants

badge="{variant}" - change the variant of the badge.

VariantDescription
softThe default variant.
solidThe solid variant.
outlineThe outline variant.
~The unstyle or base variant
Soft BadgeSolid BadgeOutline BadgeBase Badge
<template>
  <div flex flex-wrap gap-2>
    <NBadge badge="soft" label="Soft Badge" />

    <NBadge badge="solid" label="Solid Badge" />

    <NBadge badge="outline" label="Outline Badge" />

    <NBadge badge="~" label="Base Badge" />
  </div>
</template>

Colors

badge="{variant}-{color}" - change the color of the badge.

You can use any color provided by the Tailwind CSS color palette, the default is primary. You can also add your own colors to the palette through the Configuration section.
Dynamic colors:
soft-primary (default)solid-pinkoutline-infosoft-successoutline-yellowsolid-erroroutline-indigo

Static colors:
soft-graysolid-blackoutline-white
<template>
  <div flex="~ col" space-y-4>
    <span class="text-sm font-medium">Dynamic colors:</span>

    <div flex flex-wrap gap-2>
      <NBadge badge="soft-primary" label="soft-primary (default)" />

      <NBadge badge="solid-pink" label="solid-pink" />

      <NBadge badge="outline-info" label="outline-info" />

      <NBadge badge="soft-success" label="soft-success" />

      <NBadge badge="outline-yellow" label="outline-yellow" />

      <NBadge badge="solid-error" label="solid-error" />

      <NBadge badge="soft-indigo" label="outline-indigo" />
    </div>

    <hr border="base">

    <span class="text-sm font-medium">Static colors:</span>

    <div flex flex-wrap gap-2>
      <NBadge badge="soft-gray" label="soft-gray" />

      <NBadge badge="solid-black" label="solid-black" />

      <NBadge badge="outline-white" label="outline-white" />
    </div>
  </div>
</template>

Sizes

size="{size}" - change the size of the button.

πŸš€ You can freely adjust the size of the badge using any size imaginable. No limits exist, and you can use breakpoints such as sm:sm, xs:lg to change size based on screen size or states such as hover:lg, focus:3xl to change size based on input state and more.

The padding and font-size of the badge scale depends on the size. If you want to change the font-size and padding simultaneously, you can always customize it using utility classes.
BadgeBadgeBadge
<template>
<div flex-1 space-x-4 space-y-2>
  <NBadge size="sm" badge="soft" label="Badge" />

  <NBadge size="lg" badge="solid" label="Badge" />

  <NBadge size="20px" badge="outline" label="Badge" />
</div>
</template>

Icon

icon={icon} - add an icon to the badge.

By default we use heroicons and tabler for the icons, you can use any icon provided by Iconify through icones, refer to configuration for more information.
v1.2.0OfflineOnline
<template>
  <div flex="~ wrap" gap-2>
    <NBadge label="v1.2.0" icon="i-heroicons-sparkles-solid text-primary" class="rounded-full" />

    <NBadge badge="soft-gray" label="Offline" icon="i-tabler-circle-filled text-7px text-gray" />

    <NBadge badge="soft-gray" label="Online" icon="i-tabler-circle-filled text-7px text-green" />
  </div>
</template>

Closable

closable - add a close button to the badge.

BadgeBadgeBadgeBadgeBadgeBadge
<template>
  <div flex flex-wrap gap-2>
    <NBadge badge="soft" label="Badge" closable />

    <NBadge badge="solid" label="Badge" closable />

    <NBadge badge="outline" label="Badge" closable />

    <NBadge badge="soft-gray" label="Badge" closable />

    <NBadge badge="solid-black" label="Badge" closable />

    <NBadge badge="outline-white" label="Badge" closable />
  </div>
</template>

Events

Event NameDescription
@closeemit an event when the close icon is clicked. Use in conjunction with closable.

Slots

Default

Evan You Anthony Fu Daniel Roe SΓ©bastien Chopin Pooya Parsa Eduardo San Martin Morote Guillaume Chau
<script setup lang="ts">
const openSourser = [
  {
    name: 'Evan You',
    avatar: 'https://avatars.githubusercontent.com/u/499550?v=4',
  },
  {
    name: 'Anthony Fu',
    avatar: 'https://avatars.githubusercontent.com/u/11247099?v=4',
  },
  {
    name: 'Daniel Roe',
    avatar: 'https://avatars.githubusercontent.com/u/28706372?v=4',
  },
  {
    name: 'SΓ©bastien Chopin',
    avatar: 'https://avatars.githubusercontent.com/u/904724?v=4',
  },
  {
    name: 'Pooya Parsa',
    avatar: 'https://avatars.githubusercontent.com/u/5158436?v=4',
  },
  {
    name: 'Eduardo San Martin Morote',
    avatar: 'https://avatars.githubusercontent.com/u/664177?v=4',
  },
  {
    name: 'Guillaume Chau',
    avatar: 'https://avatars.githubusercontent.com/u/2798204?v=4',
  },
]

function close(name: string) {
  // eslint-disable-next-line no-alert
  alert(name)
}
</script>

<template>
  <div flex="~ wrap" gap-2>
    <NBadge
      v-for="{ name, avatar } in openSourser"
      :key="name"
      badge="solid-black"
      closable
      @close="close(name)"
    >
      <!-- TODO convert to NAvatar soon -->
      <img
        class="h-5 rounded-full bg-base p-0.5px"
        :src="avatar"
      >

      {{ name }}
    </NBadge>
  </div>
</template>

Props

export interface NBadgeProps {
  /**
   * Allows you to add `UnaUI` badge preset properties,
   * Think of it as a shortcut for adding options or variants to the preset if available.
   *
   * @see https://github.com/una-ui/una-ui/blob/main/packages/preset/src/_shortcuts/badge.ts
   * @example
   * badge="solid-yellow"
   */
  badge?: string
  /**
   * Add a label to the badge.
   */
  label?: string
  /**
   * Display an icon on the left side of the badge,
   * this also allows you to add utility classes to customize icon.
   *
   * @example
   * icon="i-heroicons-information-circle text-green-500 dark:text-green-400 text-2xl"
   */
  icon?: string

  /**
   * Display `close` icon on the right side of the badge,
   *
   * @default false
   */
  closable?: boolean

  /**
   * `UnaUI` preset configuration
   *
   * @see https://github.com/una-ui/una-ui/blob/main/packages/preset/src/_shortcuts/badge.ts
   */
  una?: {
    // base
    badgeDefaultVariant?: string
    badge?: string
    badgeIconBase?: string
    badgeClose?: string
    badgeCloseIconBase?: string

    // icons
    badgeCloseIcon?: string
  }
}

Presets

type BadgePrefix = 'badge'

export const staticBadge: Record<`${BadgePrefix}-${string}` | BadgePrefix, string> = {
  // config
  'badge-default-variant': 'badge-soft',
  'badge-close-icon': 'i-close',

  // base
  'badge': 'text-xs leading-tight py-0.3333333333333333em px-0.6666666666666666em gap-x-0.25em inline-flex items-center rounded-md font-medium text-brand',
  'badge-icon-base': 'text-1em',
  'badge-close': 'relative rounded-sm h-1.16em w-1.16em grid place-items-center -mr-0.375em hover:bg-brand/20',
  'badge-close-icon-base': 'text-brand/75 group-hover:text-brand/90',

  // variants
  'badge-soft-gray': 'bg-muted text-muted n-gray-900 dark:n-gray-50 ring-1 ring-gray-700/10 dark:ring-gray-400/30',
  'badge-solid-black': 'bg-inverted text-inverted n-gray-300 dark:n-gray-600',
  'badge-outline-white': 'bg-base text-base ring-1 ring-base n-gray-600 dark:n-gray-300',
}

export const dynamicBadge: [RegExp, (params: RegExpExecArray) => string][] = [
  // variants
  [/^badge-solid(-(\S+))?$/, ([, , c = 'primary']) => `bg-${c}-100 dark:bg-${c}-800 n-${c}-700 dark:n-${c}-200`],
  [/^badge-soft(-(\S+))?$/, ([, , c = 'primary']) => `bg-${c}-50 n-${c}-700 dark:n-${c}-400 ring-1 ring-${c}-700/10 dark:bg-${c}-400/10 dark:ring-${c}-400/30`],
  [/^badge-outline(-(\S+))?$/, ([, , c = 'primary']) => `bg-transparent n-${c}-700 dark:n-${c}-400 ring-1 ring-${c}-700/10 dark:ring-${c}-400/30`],
]

export const badge = [
  ...dynamicBadge,
  staticBadge,
]

Component

<script setup lang="ts">
import { computed } from 'vue'

import type { NBadgeProps } from '../../types'
import NIcon from './Icon.vue'

const props = withDefaults(defineProps<NBadgeProps>(), {
  una: () => ({
    badgeDefaultVariant: 'badge-default-variant',
  }),
})

const emit = defineEmits<{ (...args: any): void }>()

const badgeVariants = ['solid', 'soft', 'outline'] as const
const hasVariant = computed(() => badgeVariants.some(badgeVariants => props.badge?.includes(badgeVariants)))
const isBaseVariant = computed(() => props.badge?.includes('~'))
</script>

<template>
  <span
    :badge="badge"
    class="badge"
    :class="[
      !hasVariant && !isBaseVariant ? una?.badgeDefaultVariant : '',
      una?.badge,
    ]"
  >
    <NIcon
      v-if="icon"
      badge="icon-base"
      :class="una?.badgeIconBase"
      :name="icon"
    />

    <slot>
      {{ label }}
    </slot>

    <button
      v-if="closable"
      badge="close"
      :class="una?.badgeClose"
      group
      @click="emit('close')"
    >
      <NIcon
        :name="una?.badgeCloseIcon ?? 'badge-close-icon'"
        :class="una?.badgeCloseIconBase"
        badge="close-icon-base"
      />
      <span class="absolute -inset-0.25em" />
    </button>
  </span>
</template>