Chip

GitHub
An indicator of a numeric value or a state.

Usage

Wrap any component with a Chip to display an indicator.

<template>
  <PChip>
    <PButton icon="i-lucide-mail" color="neutral" variant="subtle" />
  </PChip>
</template>

Color

Use the color prop to change the color of the Chip.

<template>
  <PChip color="neutral">
    <PButton icon="i-lucide-mail" color="neutral" variant="subtle" />
  </PChip>
</template>

Size

Use the size prop to change the size of the Chip.

<template>
  <PChip size="3xl">
    <PButton icon="i-lucide-mail" color="neutral" variant="subtle" />
  </PChip>
</template>

Text

Use the text prop to set the text of the Chip.

5
<template>
  <PChip :text="5" size="3xl">
    <PButton icon="i-lucide-mail" color="neutral" variant="subtle" />
  </PChip>
</template>

Position

Use the position prop to change the position of the Chip.

<template>
  <PChip position="bottom-left">
    <PButton icon="i-lucide-mail" color="neutral" variant="subtle" />
  </PChip>
</template>

Inset

Use the inset prop to display the Chip inside the component. This is useful when dealing with rounded components.

<template>
  <PChip inset>
    <PAvatar src="https://github.com/benjamincanac.png" loading="lazy" />
  </PChip>
</template>

Standalone

Use the standalone prop alongside the inset prop to display the Chip inline.

<template>
  <PChip standalone inset />
</template>
It's used this way in the CommandPalette, InputMenu, Select or SelectMenu components for example.

Examples

Control visibility

You can control the visibility of the Chip using the show prop.

<script setup lang="ts">
const statuses = ['online', 'away', 'busy', 'offline'];
const status = ref(statuses[0]);

const color = computed(() => status.value ? { online: 'success', away: 'warning', busy: 'error', offline: 'neutral' }[status.value] as any : 'online');

const show = computed(() => status.value !== 'offline');

// Note: This is for demonstration purposes only. Don't do this at home.
onMounted(() => {
  setInterval(() => {
    if (status.value) {
      status.value = statuses[(statuses.indexOf(status.value) + 1) % statuses.length];
    }
  }, 1000);
});
</script>

<template>
  <PChip
    :color="color"
    :show="show"
    inset
  >
    <PAvatar
      src="https://github.com/benjamincanac.png"
      loading="lazy"
    />
  </PChip>
</template>
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'

const statuses = ['online', 'away', 'busy', 'offline'];
const status = ref(statuses[0]);

const color = computed(() => status.value ? { online: 'success', away: 'warning', busy: 'error', offline: 'neutral' }[status.value] as any : 'online');

const show = computed(() => status.value !== 'offline');

// Note: This is for demonstration purposes only. Don't do this at home.
onMounted(() => {
  setInterval(() => {
    if (status.value) {
      status.value = statuses[(statuses.indexOf(status.value) + 1) % statuses.length];
    }
  }, 1000);
});
</script>

<template>
  <PChip
    :color="color"
    :show="show"
    inset
  >
    <PAvatar
      src="https://github.com/benjamincanac.png"
      loading="lazy"
    />
  </PChip>
</template>
In this example, the Chip has a color per status and is displayed when the status is not offline.

API

Props

Prop Default Type
as
'div'
any

The element or component this component should render as.

text
string | number

Display some text inside the chip.

color
'primary'
"primary" | "secondary" | "success" | "info" | "warning" | "error" | "neutral"
size
'md'
"md" | "3xs" | "2xs" | "xs" | "sm" | "lg" | "xl" | "2xl" | "3xl"
position
'top-right'
"top-right" | "bottom-right" | "top-left" | "bottom-left"

The position of the chip.

inset
boolean

When true, keep the chip inside the component for rounded elements.

standalone
boolean

When true, render the chip relatively to the parent.

show
boolean
ui
{ root?: SlotClass; base?: SlotClass; }

Slots

Slot Type
default
{}
content
{}

Emits

Event Type
update:show
[value: boolean]

Theme

app.config.ts
export default defineAppConfig({
  ui: {
    chip: {
      slots: {
        root: 'relative inline-flex items-center justify-center shrink-0',
        base: 'ring-background font-500 rounded-full flex whitespace-nowrap ring items-center justify-center'
      },
      variants: {
        color: {
          primary: 'bg-primary color-primary-foreground',
          secondary: 'bg-secondary color-secondary-foreground',
          success: 'bg-success color-success-foreground',
          info: 'bg-info color-info-foreground',
          warning: 'bg-warning color-warning-foreground',
          error: 'bg-error color-error-foreground',
          neutral: 'bg-background-inverted color-text-inverted'
        },
        size: {
          '3xs': 'h-[4px] min-w-[4px] text-[4px]',
          '2xs': 'h-[5px] min-w-[5px] text-[5px]',
          xs: 'h-[6px] min-w-[6px] text-[6px]',
          sm: 'h-[7px] min-w-[7px] text-[7px]',
          md: 'h-[8px] min-w-[8px] text-[8px]',
          lg: 'h-[9px] min-w-[9px] text-[9px]',
          xl: 'h-[10px] min-w-[10px] text-[10px]',
          '2xl': 'h-[11px] min-w-[11px] text-[11px]',
          '3xl': 'h-[12px] min-w-[12px] text-[12px]'
        },
        position: {
          'top-right': 'top-0 right-0',
          'bottom-right': 'bottom-0 right-0',
          'top-left': 'top-0 left-0',
          'bottom-left': 'bottom-0 left-0'
        },
        inset: {
          false: ''
        },
        standalone: {
          false: 'absolute'
        }
      },
      compoundVariants: [
        {
          position: 'top-right',
          inset: false,
          class: '-translate-y-1/2 translate-x-1/2 transform'
        },
        {
          position: 'bottom-right',
          inset: false,
          class: 'translate-y-1/2 translate-x-1/2 transform'
        },
        {
          position: 'top-left',
          inset: false,
          class: '-translate-y-1/2 -translate-x-1/2 transform'
        },
        {
          position: 'bottom-left',
          inset: false,
          class: 'translate-y-1/2 -translate-x-1/2 transform'
        }
      ],
      defaultVariants: {
        size: 'md',
        color: 'primary',
        position: 'top-right'
      }
    }
  }
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from 'pohon-ui/vite'

export default defineConfig({
  plugins: [
    vue(),
    ui({
      ui: {
        chip: {
          slots: {
            root: 'relative inline-flex items-center justify-center shrink-0',
            base: 'ring-background font-500 rounded-full flex whitespace-nowrap ring items-center justify-center'
          },
          variants: {
            color: {
              primary: 'bg-primary color-primary-foreground',
              secondary: 'bg-secondary color-secondary-foreground',
              success: 'bg-success color-success-foreground',
              info: 'bg-info color-info-foreground',
              warning: 'bg-warning color-warning-foreground',
              error: 'bg-error color-error-foreground',
              neutral: 'bg-background-inverted color-text-inverted'
            },
            size: {
              '3xs': 'h-[4px] min-w-[4px] text-[4px]',
              '2xs': 'h-[5px] min-w-[5px] text-[5px]',
              xs: 'h-[6px] min-w-[6px] text-[6px]',
              sm: 'h-[7px] min-w-[7px] text-[7px]',
              md: 'h-[8px] min-w-[8px] text-[8px]',
              lg: 'h-[9px] min-w-[9px] text-[9px]',
              xl: 'h-[10px] min-w-[10px] text-[10px]',
              '2xl': 'h-[11px] min-w-[11px] text-[11px]',
              '3xl': 'h-[12px] min-w-[12px] text-[12px]'
            },
            position: {
              'top-right': 'top-0 right-0',
              'bottom-right': 'bottom-0 right-0',
              'top-left': 'top-0 left-0',
              'bottom-left': 'bottom-0 left-0'
            },
            inset: {
              false: ''
            },
            standalone: {
              false: 'absolute'
            }
          },
          compoundVariants: [
            {
              position: 'top-right',
              inset: false,
              class: '-translate-y-1/2 translate-x-1/2 transform'
            },
            {
              position: 'bottom-right',
              inset: false,
              class: 'translate-y-1/2 translate-x-1/2 transform'
            },
            {
              position: 'top-left',
              inset: false,
              class: '-translate-y-1/2 -translate-x-1/2 transform'
            },
            {
              position: 'bottom-left',
              inset: false,
              class: 'translate-y-1/2 -translate-x-1/2 transform'
            }
          ],
          defaultVariants: {
            size: 'md',
            color: 'primary',
            position: 'top-right'
          }
        }
      }
    })
  ]
})

Changelog

No recent changes