> ## 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.

# Snackbar

> A prominent inline message with optional title, description, action buttons, and close control.

```tsx theme={null}
import { Snackbar } from "@fanvue/ui";
import type { SnackbarProps, SnackbarVariant } from "@fanvue/ui";
```

## Examples

## Default

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

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

const DefaultMessage = (
  <span className="typography-body-small-14px-semibold">
    <span>@user.with.username</span> changed their subscription price to <span>$43.99</span> per
    month
  </span>
);

<Snackbar primaryLabel="Accept" secondaryLabel="Dismiss">{DefaultMessage}</Snackbar>
```

## Vip Earn Without Icon

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-snackbar--vip-earn-without-icon&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="220" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="Snackbar — Vip Earn Without Icon" />
</Frame>

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

<Snackbar
  variant="vipEarn"
  title="You're killing it! You've earned 1,000pts"
  description="Find out how to redeem them, and earn more..."
  primaryLabel="Redeem points"
/>
```

## All Variants

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

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

const DefaultMessage = (
  <span className="typography-body-small-14px-semibold">
    <span>@user.with.username</span> changed their subscription price to <span>$43.99</span> per
    month
  </span>
);

const VipBadge = <VipBadgeIcon />;

const VARIANT_CONTENT = [
  {
    variant: "default",
    props: { children: DefaultMessage },
    primary: "Accept",
    secondary: "Dismiss",
  },
  {
    variant: "vipEarn",
    props: {
      icon: VipBadge,
      title: "You're killing it! You've earned 1,000pts",
      description: "Find out how to redeem them, and earn more...",
    },
    primary: "Redeem points",
    secondary: "Maybe later",
  },
  {
    variant: "welcome",
    props: {
      title: "Welcome to Fanvue 👋",
      description: "Let's get you started!",
    },
    primary: "Become a creator",
    secondary: "Discover creators",
  },
] as const;

<div className="flex flex-col gap-10">
  {VARIANT_CONTENT.map(({ variant, props, primary, secondary }) => (
    <div key={variant} className="flex flex-col gap-3">
      <h3 className="typography-body-small-14px-semibold text-content-primary">{variant}</h3>
      <Snackbar
        variant={variant}
        {...props}
        primaryLabel={primary}
        secondaryLabel={secondary}
      />
      <Snackbar variant={variant} {...props} primaryLabel={primary} />
      <Snackbar variant={variant} {...props} showActions={false} />
      <Snackbar
        variant={variant}
        {...props}
        primarySlot={
          <Button variant="primary" size="40">
            Custom Primary
          </Button>
        }
        secondarySlot={
          <a href="#dismiss" className="typography-links-link-md text-content-secondary">
            Custom link
          </a>
        }
      />
      <Snackbar variant={variant} {...props} primaryLabel={primary} closable />
    </div>
  ))}
</div>
```

## Default Closable

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

```tsx theme={null}
import { useState } from "react";
import { Snackbar } from "@fanvue/ui";

const DefaultMessage = (
  <span className="typography-body-small-14px-semibold">
    <span>@user.with.username</span> changed their subscription price to <span>$43.99</span> per
    month
  </span>
);

function Example() {
  const [visible, setVisible] = useState(true);
  return visible ? (
    <Snackbar
      primaryLabel="Accept"
      secondaryLabel="Dismiss"
      closable
      onClose={() => setVisible(false)}
    >
      {DefaultMessage}
    </Snackbar>
  ) : (
    <div className="text-content-tertiary text-sm">
      Snackbar dismissed!{" "}
      <button
        type="button"
        onClick={() => setVisible(true)}
        className="cursor-pointer text-content-primary underline"
      >
        Show again
      </button>
    </div>
  );
}
```

## Multiple Dismissible

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

```tsx theme={null}
import { useState } from "react";
import { Snackbar, VipBadgeIcon } from "@fanvue/ui";

const DefaultMessage = (
  <span className="typography-body-small-14px-semibold">
    <span>@user.with.username</span> changed their subscription price to <span>$43.99</span> per
    month
  </span>
);

const VipBadge = <VipBadgeIcon />;

function Example() {
  const [snackbars, setSnackbars] = useState({
    vipEarn: true,
    default: true,
    welcome: true,
  });

  return (
    <div className="flex max-w-xl flex-col gap-4">
      {snackbars.vipEarn && (
        <Snackbar
          variant="vipEarn"
          icon={VipBadge}
          title="You're killing it! You've earned 1,000pts"
          description="Find out how to redeem them, and earn more..."
          primaryLabel="Redeem points"
          closable
          onClose={() => setSnackbars({ ...snackbars, vipEarn: false })}
        />
      )}
      {snackbars.default && (
        <Snackbar
          primaryLabel="Accept"
          secondaryLabel="Dismiss"
          closable
          onClose={() => setSnackbars({ ...snackbars, default: false })}
        >
          {DefaultMessage}
        </Snackbar>
      )}
      {snackbars.welcome && (
        <Snackbar
          variant="welcome"
          title="Welcome to Fanvue 👋"
          description="Let's get you started!"
          primaryLabel="Become a creator"
          secondaryLabel="Discover creators"
          closable
          onClose={() => setSnackbars({ ...snackbars, welcome: false })}
        />
      )}
      {!snackbars.vipEarn && !snackbars.default && !snackbars.welcome && (
        <div className="text-content-tertiary text-sm">
          All snackbars dismissed!{" "}
          <button
            type="button"
            onClick={() => setSnackbars({ vipEarn: true, default: true, welcome: true })}
            className="cursor-pointer text-content-primary underline"
          >
            Reset all
          </button>
        </div>
      )}
    </div>
  );
}
```

## Props

## Snackbar

A prominent inline message with optional title, description, action buttons, and close control. Supports three layout variants: `default`, `vipEarn`, and `welcome`.

<ParamField path="closable" type="boolean" default="false">
  Whether to show the close button.
</ParamField>

<ParamField path="closeLabel" type="string" default="Close snackbar">
  Accessible label for the close button.
</ParamField>

<ParamField path="description" type="ReactNode">
  Descriptive body text.
</ParamField>

<ParamField path="icon" type="ReactNode">
  Icon element displayed at the leading edge (used by the `vipEarn` variant).
</ParamField>

<ParamField path="onClose" type="(() => void)">
  Callback fired when the close button is clicked.
</ParamField>

<ParamField path="primaryLabel" type="string">
  Primary CTA label — renders a default `Button`.
</ParamField>

<ParamField path="primaryOnClick" type="(() => void)">
  Click handler for the primary CTA (used together with `primaryLabel`).
</ParamField>

<ParamField path="primarySlot" type="ReactNode">
  Custom element rendered as the primary CTA. Overrides `primaryLabel` / `primaryOnClick`.
</ParamField>

<ParamField path="secondaryLabel" type="string">
  Secondary CTA label — renders a default `Button`.
</ParamField>

<ParamField path="secondaryOnClick" type="(() => void)">
  Click handler for the secondary CTA (used together with `secondaryLabel`).
</ParamField>

<ParamField path="secondarySlot" type="ReactNode">
  Custom element rendered as the secondary CTA. Overrides `secondaryLabel` / `secondaryOnClick`.
</ParamField>

<ParamField path="showActions" type="boolean" default="true">
  Whether to show primary/secondary action buttons.
</ParamField>

<ParamField path="title" type="ReactNode">
  Title content.
</ParamField>

<ParamField path="variant" type="&#x22;default&#x22; | &#x22;vipEarn&#x22; | &#x22;welcome&#x22;" default="default">
  Layout variant of the snackbar.
</ParamField>

## Exported types

Also exported from `@fanvue/ui`: `SnackbarProps`, `SnackbarVariant`.

***

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