Attachments

A flexible, composable attachment component for displaying files, images, videos, audio, and source documents.

The Attachment component provides a unified way to display file attachments and source documents with multiple layout variants.

Install using CLI

AI Elements Vue
shadcn-vue CLI
npx ai-elements-vue@latest add attachments

Install Manually

Copy and paste the following code in the same folder.

Attachments.vue
Attachment.vue
AttachmentPreview.vue
AttachmentInfo.vue
AttachmentRemove.vue
AttachmentHoverCard.vue
AttachmentHoverCardTrigger.vue
AttachmentHoverCardContent.vue
AttachmentEmpty.vue
context.ts
types.ts
utils.ts
index.ts
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import type { AttachmentVariant } from './types'
import { cn } from '@repo/shadcn-vue/lib/utils'
import { computed, provide } from 'vue'
import { AttachmentsKey } from './context'

interface Props extends /* @vue-ignore */ HTMLAttributes {
  variant?: AttachmentVariant
  class?: HTMLAttributes['class']
}

const props = withDefaults(defineProps<Props>(), {
  variant: 'grid',
})

const variant = computed(() => props.variant)

provide(AttachmentsKey, { variant })
</script>

<template>
  <div
    :class="
      cn(
        'flex items-start',
        variant === 'list' ? 'flex-col gap-2' : 'flex-wrap gap-2',
        variant === 'grid' && 'ml-auto w-fit',
        props.class,
      )
    "
    v-bind="$attrs"
  >
    <slot />
  </div>
</template>

Usage with AI SDK

Display user-uploaded files in chat messages or input areas.

pages/index.vue
<script setup lang="ts">
import type { AttachmentData } from '@/components/ai-elements/attachments'
import {
  Attachment,
  AttachmentPreview,
  AttachmentRemove,
  Attachments,
} from '@/components/ai-elements/attachments'

interface MessageProps {
  attachments: AttachmentData[]
  onRemove?: (id: string) => void
}

const props = defineProps<MessageProps>()
</script>

<template>
  <Attachments variant="grid">
    <Attachment
      v-for="file in props.attachments"
      :key="file.id"
      :data="file"
      @remove="props.onRemove && props.onRemove(file.id)"
    >
      <AttachmentPreview />
      <AttachmentRemove />
    </Attachment>
  </Attachments>
</template>

Features

  • Three display variants: grid (thumbnails), inline (badges), and list (rows)
  • Supports both FileUIPart and SourceDocumentUIPart from the AI SDK
  • Automatic media type detection (image, video, audio, document, source)
  • Hover card support for inline previews
  • Remove button with customizable callback
  • Composable architecture for maximum flexibility
  • Accessible with proper ARIA labels
  • TypeScript support with exported utility functions

Examples

Grid Variant

Best for displaying attachments in messages with visual thumbnails.

Inline Variant

Best for compact badge-style display in input areas with hover previews.

List Variant

Best for file lists with full metadata display.

Props

<Attachments />

Container component that sets the layout variant.

variant'grid' | 'inline' | 'list'
'grid'
The display layout variant.
...propsHTMLAttributes
Spread to the underlying div element.

<Attachment />

Individual attachment item wrapper.

dataAttachmentData
The attachment data (FileUIPart or SourceDocumentUIPart with id).
@removeevent: void
Callback fired when the remove button is clicked.
...propsHTMLAttributes
Spread to the underlying div element.

<AttachmentPreview />

Displays the media preview (image, video, or icon).

fallbackIconVNode
Custom icon to display when no preview is available.
...propsHTMLAttributes
Spread to the underlying div element.

<AttachmentInfo />

Displays the filename and optional media type.

showMediaTypeboolean
false
Whether to show the media type below the filename.
...propsHTMLAttributes
Spread to the underlying div element.

<AttachmentRemove />

Remove button that appears on hover.

labelstring
'Remove'
Screen reader label for the button.
...propsInstanceType<typeof Button>
Spread to the underlying Button component.

<AttachmentHoverCard />

Wrapper for hover preview functionality.

openDelaynumber
0
Delay in ms before opening the hover card.
closeDelaynumber
0
Delay in ms before closing the hover card.
...propsInstanceType<typeof HoverCard>
Spread to the underlying HoverCard component.

<AttachmentHoverCardTrigger />

Trigger element for the hover card.

...propsInstanceType<typeof HoverCardTrigger>
Spread to the underlying HoverCardTrigger component.

<AttachmentHoverCardContent />

Content displayed in the hover card.

align'start' | 'center' | 'end'
'start'
Alignment of the hover card content.
...propsInstanceType<typeof HoverCardContent>
Spread to the underlying HoverCardContent component.

<AttachmentEmpty />

Empty state component when no attachments are present.

...propsHTMLAttributes
Spread to the underlying div element.

Utility Functions

getMediaCategory(data)

Returns the media category for an attachment.

import { getMediaCategory } from '@/components/ai-elements/attachments'

const category = getMediaCategory(attachment)
// Returns: 'image' | 'video' | 'audio' | 'document' | 'source' | 'unknown'

getAttachmentLabel(data)

Returns the display label for an attachment.

import { getAttachmentLabel } from '@/components/ai-elements/attachments'

const label = getAttachmentLabel(attachment)
// Returns filename or fallback like 'Image' or 'Attachment'