Rendered from the shared Frontfriend stories with React Base, the same
preview Studio shows. Styling comes from your Design System; the code below
is native to Reka UI.
Installation
Complete project setup first. Your configuration
must select vue/reka and include your Design System ID.
pnpm exec frontfriend download attachment -f vue --primitive reka
Review dependencies reported by the downloader and keep your source
changes in version control.
Usage
<script setup lang="ts">
import { Attachment } from "@/components/ui/attachment";
import { AttachmentMedia } from "@/components/ui/attachment";
import { Icon } from "@/components/ui/icon";
import { AttachmentContent } from "@/components/ui/attachment";
import { AttachmentTitle } from "@/components/ui/attachment";
import { AttachmentDescription } from "@/components/ui/attachment";
const args = {
"orientation": "horizontal",
"state": "done",
"title": "report.pdf",
"description": "PDF · 12 KB",
} satisfies Partial<
InstanceType<typeof Attachment> extends { $props: infer Props } ? Props : {}
> &
Record<string, unknown> & {
orientation?: "horizontal" | "vertical";
state?: "idle" | "uploading" | "processing" | "error" | "done";
};
</script>
<template>
<Attachment :orientation="args.orientation" :state="args.state"
><AttachmentMedia><Icon name="FileText" /></AttachmentMedia
><AttachmentContent
><AttachmentTitle>{{ args.title }}</AttachmentTitle
><AttachmentDescription>{{
args.description
}}</AttachmentDescription></AttachmentContent
></Attachment
>
</template>
Examples
<script setup lang="ts">
import { ref } from "vue";
import { Attachment } from "@/components/ui/attachment";
import { AttachmentTrigger } from "@/components/ui/attachment";
import { AttachmentMedia } from "@/components/ui/attachment";
import { Icon } from "@/components/ui/icon";
import { AttachmentContent } from "@/components/ui/attachment";
import { AttachmentTitle } from "@/components/ui/attachment";
import { AttachmentDescription } from "@/components/ui/attachment";
import { Button } from "@/components/ui/button";
const args = {
} satisfies Partial<
InstanceType<typeof Attachment> extends { $props: infer Props } ? Props : {}
> &
Record<string, unknown>;
const opened = ref(0);
const submitted = ref(0);
</script>
<template>
<form
class="flex w-[360px] max-w-[calc(100vw-2rem)] flex-col gap-3"
@submit.prevent="submitted += 1"
>
<Attachment>
<AttachmentTrigger aria-label="Open report.pdf" @click="opened += 1" />
<AttachmentMedia><Icon name="FileText" size="4" /></AttachmentMedia>
<AttachmentContent
><AttachmentTitle>report.pdf</AttachmentTitle
><AttachmentDescription
>Open attachment</AttachmentDescription
></AttachmentContent
>
</Attachment>
<Button type="submit" variant="outline">Submit form</Button>
<output class="text-sm text-neutral-mid"
>Opened: {{ opened }}. Submitted: {{ submitted }}.</output
>
</form>
</template>
Default
<script setup lang="ts">
import { Attachment } from "@/components/ui/attachment";
import { AttachmentMedia } from "@/components/ui/attachment";
import { Icon } from "@/components/ui/icon";
import { AttachmentContent } from "@/components/ui/attachment";
import { AttachmentTitle } from "@/components/ui/attachment";
import { AttachmentDescription } from "@/components/ui/attachment";
import { AttachmentActions } from "@/components/ui/attachment";
import { AttachmentAction } from "@/components/ui/attachment";
const args = {
} satisfies Partial<
InstanceType<typeof Attachment> extends { $props: infer Props } ? Props : {}
> &
Record<string, unknown>;
</script>
<template>
<div class="flex w-full max-w-sm flex-col gap-3">
<Attachment class="w-full">
<AttachmentMedia>
<Icon name="FileCode" size="4" />
</AttachmentMedia>
<AttachmentContent>
<AttachmentTitle>message-renderer.vue</AttachmentTitle>
<AttachmentDescription>TypeScript · 12 KB</AttachmentDescription>
</AttachmentContent>
<AttachmentActions>
<AttachmentAction aria-label="Remove message-renderer.vue">
<Icon name="X" size="4" />
</AttachmentAction>
</AttachmentActions>
</Attachment>
</div>
</template>
Image Group
<script setup lang="ts">
import { AttachmentGroup } from "@/components/ui/attachment";
import { Attachment } from "@/components/ui/attachment";
import { AttachmentMedia } from "@/components/ui/attachment";
import { AttachmentContent } from "@/components/ui/attachment";
import { AttachmentTitle } from "@/components/ui/attachment";
import { AttachmentDescription } from "@/components/ui/attachment";
const images = [
{
name: "workspace.png",
meta: "PNG · 820 KB",
src: "https://github.com/shadcn.png",
alt: "Workspace",
},
{
name: "desk-reference.jpg",
meta: "JPG · 1.1 MB",
src: "https://github.com/vercel.png",
alt: "Desk",
},
];
const args = {
} satisfies Partial<
InstanceType<typeof Attachment> extends { $props: infer Props } ? Props : {}
> &
Record<string, unknown>;
</script>
<template>
<div class="flex w-full max-w-sm flex-col gap-3">
<AttachmentGroup>
<Attachment
v-for="image in images"
:key="image.name"
orientation="vertical"
>
<AttachmentMedia variant="image">
<img :src="image.src" :alt="image.alt" />
</AttachmentMedia>
<AttachmentContent>
<AttachmentTitle>{{ image.name }}</AttachmentTitle>
<AttachmentDescription>{{ image.meta }}</AttachmentDescription>
</AttachmentContent>
</Attachment>
</AttachmentGroup>
</div>
</template>
Uploading
<script setup lang="ts">
import { Attachment } from "@/components/ui/attachment";
import { AttachmentMedia } from "@/components/ui/attachment";
import { Spinner } from "@/components/ui/spinner";
import { AttachmentContent } from "@/components/ui/attachment";
import { AttachmentTitle } from "@/components/ui/attachment";
import { AttachmentDescription } from "@/components/ui/attachment";
import { AttachmentActions } from "@/components/ui/attachment";
import { AttachmentAction } from "@/components/ui/attachment";
import { Icon } from "@/components/ui/icon";
const args = {
} satisfies Partial<
InstanceType<typeof Attachment> extends { $props: infer Props } ? Props : {}
> &
Record<string, unknown>;
</script>
<template>
<div class="flex w-full max-w-sm flex-col gap-3">
<Attachment state="uploading" class="w-full">
<AttachmentMedia>
<Spinner />
</AttachmentMedia>
<AttachmentContent>
<AttachmentTitle>sales-dashboard.pdf</AttachmentTitle>
<AttachmentDescription>Uploading · 64%</AttachmentDescription>
</AttachmentContent>
<AttachmentActions>
<AttachmentAction aria-label="Cancel upload">
<Icon name="X" size="4" />
</AttachmentAction>
</AttachmentActions>
</Attachment>
</div>
</template>
States
<script setup lang="ts">
import { Attachment } from "@/components/ui/attachment";
import { AttachmentMedia } from "@/components/ui/attachment";
import { Icon } from "@/components/ui/icon";
import { AttachmentContent } from "@/components/ui/attachment";
import { AttachmentTitle } from "@/components/ui/attachment";
import { AttachmentDescription } from "@/components/ui/attachment";
const args = {
} satisfies Partial<
InstanceType<typeof Attachment> extends { $props: infer Props } ? Props : {}
> &
Record<string, unknown>;
const states = ["idle", "uploading", "processing", "error", "done"] as const;
</script>
<template>
<div class="flex w-full max-w-sm flex-col gap-3">
<Attachment
v-for="state in states"
:key="state"
:state="state"
class="w-full"
>
<AttachmentMedia>
<Icon name="FileText" size="4" />
</AttachmentMedia>
<AttachmentContent>
<AttachmentTitle>report.pdf</AttachmentTitle>
<AttachmentDescription>{{ state }}</AttachmentDescription>
</AttachmentContent>
</Attachment>
</div>
</template>
API reference
Frontfriend-owned props. Native HTML and inherited primitive props
remain documented by Reka UI.
Attachment
| Prop | Type | Default | Description |
class | HTMLAttributes["class"] | — | |
orientation | AttachmentVariants["orientation"] | — | |
size | AttachmentVariants["size"] | — | |
state | "idle" | "uploading" | "processing" | "error" | "done" | — | |
AttachmentAction
| Prop | Type | Default | Description |
class | HTMLAttributes["class"] | — | |
size | ButtonVariants["size"] | — | |
variant | ButtonVariants["variant"] | — | |
AttachmentActions
| Prop | Type | Default | Description |
class | HTMLAttributes["class"] | — | |
AttachmentContent
| Prop | Type | Default | Description |
class | HTMLAttributes["class"] | — | |
AttachmentDescription
| Prop | Type | Default | Description |
class | HTMLAttributes["class"] | — | |
AttachmentGroup
| Prop | Type | Default | Description |
class | HTMLAttributes["class"] | — | |
AttachmentMedia
| Prop | Type | Default | Description |
class | HTMLAttributes["class"] | — | |
variant | AttachmentMediaVariants["variant"] | — | |
AttachmentTitle
| Prop | Type | Default | Description |
class | HTMLAttributes["class"] | — | |
AttachmentTrigger
| Prop | Type | Default | Description |
class | HTMLAttributes["class"] | — | |
type | ButtonHTMLAttributes["type"] | — | |
Configuration determines the actual classes and available styling hooks.
See Theming & component configuration before introducing
a repeated local override.