> ## Documentation Index
> Fetch the complete documentation index at: https://api.fanvue.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# ChatEmbed

> A card embedded in a chat thread that links out to a creator profile or a fan experience such as a live stream or game.

```tsx theme={null}
import { ChatEmbed, ChatEmbedSkeleton, ChatEmbedUnavailable } from "@fanvue/ui";
import type {
  ChatEmbedProps,
  ChatEmbedSkeletonProps,
  ChatEmbedSocialProof,
  ChatEmbedUnavailableProps,
  ChatEmbedVariant,
} from "@fanvue/ui";
```

## Examples

## Loading

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-chatembed--loading&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="380" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="ChatEmbed — Loading" />
</Frame>

```tsx theme={null}
import { ChatEmbedSkeleton } from "@fanvue/ui";

<ChatEmbedSkeleton variant="experience" />
```

## With Social Proof

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-chatembed--with-social-proof&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="380" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="ChatEmbed — With Social Proof" />
</Frame>

```tsx theme={null}
import { Button, LiveStatus } from "@fanvue/ui";
import type { ChatEmbedProps, ChatEmbedSocialProof, ChatEmbedVariant } from "@fanvue/ui";

type ChatEmbedStoryArgs = Omit<ChatEmbedProps, "variant" | "socialProof"> & {
  variant?: ChatEmbedVariant;
  socialProof?: ChatEmbedSocialProof;
};

const COVER = "https://images.unsplash.com/photo-1531746020798-e6953c6e8e04?w=800&h=320&fit=crop";

const STREAM = "https://images.unsplash.com/photo-1501386761578-eac5c94b800a?w=800&h=480&fit=crop";

const AVATAR = "https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=128&h=128&fit=crop";

const WATCHERS = [
  "https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=64&h=64&fit=crop",
  "https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=64&h=64&fit=crop",
  "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=64&h=64&fit=crop",
].map((src) => ({ src, alt: "" }));

type Story = StoryObj<ChatEmbedStoryArgs>;

const experienceArgs = {
  variant: "experience",
  verified: true,
  aiDisclosure: false,
  media: <img src={STREAM} alt="" />,
  title: "Friday night Q&A",
  subtitle: "Made by @jane_doe",
} as const;

const Live: Story = {
  args: {
    ...experienceArgs,
    badge: <LiveStatus variant="live" />,
    action: (
      <Button variant="white" size="32">
        Join
      </Button>
    ),
  },
};

<ChatEmbed as React.ComponentType<ChatEmbedStoryArgs>
  href="https://www.fanvue.com"
  media={<img src={COVER} alt="" />}
  avatar={{ src: AVATAR, alt: "Jane Doe", fallback: "JD" }}
  title="Display Name"
  subtitle="@handle"
  verified
  aiDisclosure
  action={<Button variant="white" size="32">
    View Profile
  </Button>}
  {...Live.args}
  socialProof={{ avatars: WATCHERS, label: "+3 watching" }}
/>
```

## Creator

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-chatembed--creator&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="380" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="ChatEmbed — Creator" />
</Frame>

```tsx theme={null}
import { Button } from "@fanvue/ui";

const COVER = "https://images.unsplash.com/photo-1531746020798-e6953c6e8e04?w=800&h=320&fit=crop";

const AVATAR = "https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=128&h=128&fit=crop";

<ChatEmbed as React.ComponentType<ChatEmbedStoryArgs>
  href="https://www.fanvue.com"
  media={<img src={COVER} alt="" />}
  avatar={{ src: AVATAR, alt: "Jane Doe", fallback: "JD" }}
  title="Display Name"
  subtitle="@handle"
  verified
  aiDisclosure
  action={<Button variant="white" size="32">
    View Profile
  </Button>}
/>
```

## Without Media

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-chatembed--without-media&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="380" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="ChatEmbed — Without Media" />
</Frame>

```tsx theme={null}
import { Button } from "@fanvue/ui";
import type { ChatEmbedProps, ChatEmbedSocialProof, ChatEmbedVariant } from "@fanvue/ui";

type ChatEmbedStoryArgs = Omit<ChatEmbedProps, "variant" | "socialProof"> & {
  variant?: ChatEmbedVariant;
  socialProof?: ChatEmbedSocialProof;
};

const COVER = "https://images.unsplash.com/photo-1531746020798-e6953c6e8e04?w=800&h=320&fit=crop";

const STREAM = "https://images.unsplash.com/photo-1501386761578-eac5c94b800a?w=800&h=480&fit=crop";

const GAME = "https://images.unsplash.com/photo-1511512578047-dfb367046420?w=800&h=480&fit=crop";

const AVATAR = "https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=128&h=128&fit=crop";

type Story = StoryObj<ChatEmbedStoryArgs>;

const experienceArgs = {
  variant: "experience",
  verified: true,
  aiDisclosure: false,
  media: <img src={STREAM} alt="" />,
  title: "Friday night Q&A",
  subtitle: "Made by @jane_doe",
} as const;

const Game: Story = {
  args: {
    ...experienceArgs,
    category: "Game",
    media: <img src={GAME} alt="" />,
    title: "Neon Run",
    action: (
      <Button variant="white" size="32">
        Play Now
      </Button>
    ),
  },
};

<ChatEmbed as React.ComponentType<ChatEmbedStoryArgs>
  href="https://www.fanvue.com"
  avatar={{ src: AVATAR, alt: "Jane Doe", fallback: "JD" }}
  title="Display Name"
  subtitle="@handle"
  verified
  aiDisclosure
  action={<Button variant="white" size="32">
    View Profile
  </Button>}
  {...Game.args}
/>
```

## Generic

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-chatembed--generic&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="380" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="ChatEmbed — Generic" />
</Frame>

```tsx theme={null}
import { Button } from "@fanvue/ui";

const COVER = "https://images.unsplash.com/photo-1531746020798-e6953c6e8e04?w=800&h=320&fit=crop";

const STREAM = "https://images.unsplash.com/photo-1501386761578-eac5c94b800a?w=800&h=480&fit=crop";

const AVATAR = "https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=128&h=128&fit=crop";

const experienceArgs = {
  variant: "experience",
  verified: true,
  aiDisclosure: false,
  media: <img src={STREAM} alt="" />,
  title: "Friday night Q&A",
  subtitle: "Made by @jane_doe",
} as const;

const OPEN = (
  <Button variant="white" size="32">
    Open
  </Button>
);

<ChatEmbed as React.ComponentType<ChatEmbedStoryArgs>
  href="https://www.fanvue.com"
  media={<img src={STREAM} alt="" />}
  avatar={{ src: AVATAR, alt: "Jane Doe", fallback: "JD" }}
  title="Launch your page"
  subtitle="Made by @jane_doe"
  verified
  aiDisclosure={false}
  action={OPEN}
  variant="experience"
/>
```

## Props

## ChatEmbed

A card embedded in a chat thread that links out to a creator profile or a fan experience such as a live stream or game. Media fills the card and the profile row sits on a blurred scrim along the bottom edge.

The `creator` variant is 160px tall and the `experience` variant 239px; both fill their container up to 400px wide. Pass `href` (or `onOpen`) to make the whole card clickable; the `action` stays separately clickable above it. Use `ChatEmbedSkeleton` while the embed's data loads and `ChatEmbedUnavailable` when the shared item no longer exists.

Give `media` meaningful alt text when it conveys content, or `alt=""` when the title already describes it. When `media` is a video with `verticalMedia`, pass its poster frame as `mediaBackdrop` so the video is not decoded twice. `socialProof` is shown to everyone in the chat, so prefer a count over naming other fans.

<ParamField path="title" type="ReactNode" required>
  Primary line of the profile row: a display name or an experience title.
</ParamField>

<ParamField path="action" type="ReactNode">
  Action at the end of the profile row, typically a `Button` with `variant="white"` and `size="32"`.
</ParamField>

<ParamField path="aiDisclosure" type="boolean" default="false">
  Show the EU AI-disclosure badge on the creator line.
</ParamField>

<ParamField path="aiDisclosureLabel" type="string" default="AI creator">
  Accessible label for the AI-disclosure badge.
</ParamField>

<ParamField path="avatar" type="AvatarProps">
  Avatar shown at the start of the profile row.
</ParamField>

<ParamField path="badge" type="ReactNode">
  Badge in the top-left corner, typically a `LiveStatus`.
</ParamField>

<ParamField path="category" type="ReactNode">
  Short category label shown as a tag after the badge, e.g. "Game" or "Audio".
</ParamField>

<ParamField path="href" type="string">
  Makes the whole card a link to this URL, named by the title. Not available with `onOpen`.
</ParamField>

<ParamField path="inactive" type="boolean" default="false">
  Renders the media in greyscale, e.g. once a live has ended.
</ParamField>

<ParamField path="media" type="ReactNode">
  Media filling the card, typically an `img` or `video`, over a dark surface.
</ParamField>

<ParamField path="mediaBackdrop" type="ReactNode">
  Still image blurred behind `verticalMedia`, e.g. the same image or a video's poster frame.
</ParamField>

<ParamField path="meta" type="ReactNode">
  Short copy in a translucent pill in the top-right corner, e.g. "2 hours ago".
</ParamField>

<ParamField path="onOpen" type="(() => void)">
  Not available with `href`. Makes the whole card a button named by the title, e.g. to open a dialog.
</ParamField>

<ParamField path="socialProof" type="ChatEmbedSocialProof">
  Only available on the `experience` variant. Social proof row shown above the profile row.
</ParamField>

<ParamField path="subtitle" type="ReactNode">
  Secondary line under the title, e.g. a handle or "Made by @jane\_doe ".
</ParamField>

<ParamField path="target" type="HTMLAttributeAnchorTarget">
  Where to open `href`; `"_blank"` adds `rel="noopener noreferrer"`. Not available with `onOpen`.
</ParamField>

<ParamField path="variant" type="&#x22;creator&#x22; | &#x22;experience&#x22;" default="creator">
  Layout of the embed.
</ParamField>

<ParamField path="verified" type="boolean" default="false">
  Show the verified badge on the creator line.
</ParamField>

<ParamField path="verifiedLabel" type="string" default="Verified">
  Accessible label for the verified badge.
</ParamField>

<ParamField path="verticalMedia" type="boolean" default="false">
  Frame portrait media in a centred 9:16 column over `mediaBackdrop`.
</ParamField>

## ChatEmbedSkeleton

Loading placeholder sized to match a `ChatEmbed`, shown while the data for a shared link is being fetched.

<ParamField path="label" type="string" default="Loading">
  Visually hidden text read by screen readers in place of the placeholder.
</ParamField>

<ParamField path="variant" type="&#x22;creator&#x22; | &#x22;experience&#x22;" default="creator">
  Layout to match while the embed loads.
</ParamField>

## ChatEmbedUnavailable

Placeholder sized to match a `ChatEmbed`, shown in place of the card when the shared profile or experience has been removed, hidden or unpublished. Pass `children` to localise the message.

<ParamField path="icon" type="ReactNode">
  Icon shown above the message.
</ParamField>

<ParamField path="variant" type="&#x22;creator&#x22; | &#x22;experience&#x22;" default="creator">
  Layout to match the embed it replaces.
</ParamField>

## Exported types

Also exported from `@fanvue/ui`: `ChatEmbedProps`, `ChatEmbedSkeletonProps`, `ChatEmbedSocialProof`, `ChatEmbedUnavailableProps`, `ChatEmbedVariant`.

***

**Setup:** [Installation](/docs/ui/installation) · [Theming](/docs/ui/theming)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.