# Hero 195 - Hero with tabbed dashboard preview

> Headline paragraph optional Buttons TabsList swapping wide dashboard TabsContent accented by animated border beam silhouette plus dashed ornamental frame lines bordering captured UI.

A shadcn/ui block from the [@shadcnblocks](https://shadcnblocks.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/shadcnblocks/hero195).

- Page, with a live preview: https://shadcn.exchange/r/shadcnblocks/hero195
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/shadcnblocks/hero195-light-011899acf6b78bfb.png
- Registry item: https://shadcnblocks.com/r/hero195.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://shadcnblocks.com/r/hero195.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `cn`, `lucide-react`
- Registry items: `button`, `tabs`, `https://magicui.design/r/border-beam`

## Files

### `block/hero195/hero195.tsx`

```tsx
"use client";

import {
  BarChart,
  Database,
  Layers,
  PieChart,
  SquareKanban,
  type LucideIcon,
} from "lucide-react";
import { useState } from "react";
import { cn } from "cn";

import { BorderBeam } from "@/components/magicui/border-beam";
import { Button } from "@/components/ui/button";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";

interface HeroSaasTab {
  title: string;
  image: Image;
}
interface Image {
  src: string;
  alt: string;
  srcDark?: string;
}
interface Button {
  text: string;
  url: string;
  icon?: React.ReactNode;
}
interface Buttons {
  primary?: Button;
  secondary?: Button;
}

interface HeroSaasProps {
  className?: string;
  heading: string;
  description: string;
  buttons?: Buttons;
  tabs?: HeroSaasTab[];
}

interface Hero195Props extends HeroSaasProps {}
type Props = Partial<Hero195Props>;

const defaultProps: Hero195Props = {
  heading: "The AI-powered CRM solution.",
  description:
    "Let AI help you manage accounts, deals, and handoffs in one place. Experience the future of CRM with AI-powered insights and automation.",
  buttons: {
    primary: { text: "Get started", url: "#" },
    secondary: { text: "Learn more", url: "#" },
  },
  tabs: [
    {
      title: "Pipeline",
      image: {
        src: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/saas-hero/saas-hero-1-16x9.png",
        srcDark: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/saas-hero/saas-hero-1-16x9-dark.png",
        alt: "CRM pipeline dashboard",
      },
    },
    {
      title: "Contacts",
      image: {
        src: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/saas-hero/saas-hero-2-16x9.png",
        srcDark: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/saas-hero/saas-hero-2-16x9-dark.png",
        alt: "Contacts and accounts",
      },
    },
    {
      title: "Deals",
      image: {
        src: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/saas-hero/saas-hero-3-16x9.png",
        srcDark: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/saas-hero/saas-hero-3-16x9-dark.png",
        alt: "Deal stages and forecast",
      },
    },
    {
      title: "Activity",
      image: {
        src: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/saas-hero/saas-hero-4-16x9.png",
        srcDark: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/saas-hero/saas-hero-4-16x9-dark.png",
        alt: "Activity and tasks",
      },
    },
  ],
};

const TAB_ICONS: readonly LucideIcon[] = [
  SquareKanban,
  BarChart,
  PieChart,
  Database,
  Layers,
];

const Hero195 = (props: Props) => {
  const {
    heading,
    description,
    buttons,
    tabs = [],
    className,
  } = {
    ...defaultProps,
    ...props,
  };
  const [activeTab, setActiveTab] = useState(tabs[0]?.title ?? "");
  const activeIndex = Math.max(
    0,
    tabs.findIndex((tab) => tab.title === activeTab),
  );
  const ActiveIcon = TAB_ICONS[activeIndex % TAB_ICONS.length];

  return (
    <section className={cn("overflow-hidden", className)}>
      <div className="container">
        <div className="border-x border-border py-20">
          <div className="relative mx-auto max-w-4xl px-6 pt-8 pb-4 lg:p-2">
            <h1 className="mx-auto mt-6 max-w-4xl text-center text-3xl font-bold tracking-tight text-pretty md:text-4xl lg:text-6xl lg:tracking-tighter">
              {heading}
            </h1>
            <p className="mx-auto mt-6 max-w-3xl text-center text-sm text-muted-foreground md:text-base lg:text-xl">
              {description}
            </p>
            <div className="mx-auto mt-6 flex w-full max-w-sm flex-col gap-2 sm:max-w-none sm:flex-row sm:justify-center">
              {buttons?.primary && (
                <Button className="w-full sm:w-auto" asChild>
                  <a href={buttons.primary.url}>{buttons.primary.text}</a>
                </Button>
              )}
              {buttons?.secondary && (
                <Button className="w-full sm:w-auto" variant="outline" asChild>
                  <a href={buttons.secondary.url}>{buttons.secondary.text}</a>
                </Button>
              )}
            </div>
          </div>
          {tabs.length > 0 && (
            <div className="mt-4 md:mt-16 lg:mt-20">
              <Tabs value={activeTab} onValueChange={setActiveTab}>
                <div className="hidden md:block">
                  <TabsList className="mx-auto mb-6 flex h-auto w-fit flex-wrap justify-center gap-2 p-1 md:gap-2 lg:gap-3">
                    {tabs.map((tab, i) => {
                      const Icon = TAB_ICONS[i % TAB_ICONS.length];
                      return (
                        <TabsTrigger
                          key={tab.title}
                          value={tab.title}
                          className="gap-1.5 px-2 py-1 text-sm font-normal text-muted-foreground lg:gap-2 lg:px-3 lg:py-2 lg:text-base"
                        >
                          <Icon className="size-4 lg:size-5" aria-hidden />
                          {tab.title}
                        </TabsTrigger>
                      );
                    })}
                  </TabsList>
                </div>
                <div className="relative isolate">
                  <div className="relative z-10">
                    {tabs.map((tab) => (
                      <TabsContent
                        key={tab.title}
                        value={tab.title}
                        className={cn(
                          "-mx-px bg-background transition-opacity duration-500",
                          {
                            "animate-in opacity-100 fade-in":
                              activeTab === tab.title,
                            "opacity-0": activeTab !== tab.title,
                          },
                        )}
                      >
                        <img
                          src={tab.image.src}
                          alt={tab.image.alt}
                          className="aspect-[16/10] w-full border border-border object-top shadow-[0_6px_20px_rgb(0,0,0,0.12)]"
                        />
                        <BorderBeam duration={8} size={100} />
                      </TabsContent>
                    ))}
                  </div>
                  <span className="absolute -inset-x-1/5 top-0 -z-10 h-px bg-border [mask-image:linear-gradient(to_right,transparent_1%,black_10%,black_90%,transparent_99%)]"></span>
                  <span className="absolute -inset-x-1/5 bottom-0 -z-10 h-px bg-border [mask-image:linear-gradient(to_right,transparent_1%,black_10%,black_90%,transparent_99%)]"></span>

                  <span className="absolute -inset-x-1/5 top-12 h-px border-t border-dashed border-border [mask-image:linear-gradient(to_right,transparent_1%,black_10%,black_90%,transparent_99%)]"></span>
                  <span className="absolute -inset-x-1/5 bottom-12 h-px border-t border-dashed border-border [mask-image:linear-gradient(to_right,transparent_1%,black_10%,black_90%,transparent_99%)]"></span>

                  <span className="absolute -inset-y-1/5 left-1/6 w-px border-r border-dashed border-border [mask-image:linear-gradient(to_bottom,transparent_1%,black_10%,black_90%,transparent_99%)]"></span>
                  <span className="absolute -inset-y-1/5 right-1/6 w-px border-r border-dashed border-border [mask-image:linear-gradient(to_bottom,transparent_1%,black_10%,black_90%,transparent_99%)]"></span>
                </div>
                <nav
                  className="mt-6 flex flex-col items-center gap-4 md:hidden"
                  aria-label="Feature slides"
                >
                  <div className="flex items-center gap-1.5" role="tablist">
                    {tabs.map((tab) => (
                      <button
                        key={tab.title}
                        type="button"
                        role="tab"
                        aria-selected={activeTab === tab.title}
                        aria-label={tab.title}
                        onClick={() => setActiveTab(tab.title)}
                        className={cn(
                          "h-1.5 rounded-full transition-all",
                          activeTab === tab.title
                            ? "w-8 bg-foreground"
                            : "w-1.5 bg-muted-foreground/40",
                        )}
                      />
                    ))}
                  </div>
                  <div className="flex size-10 items-center justify-center rounded-lg border border-border bg-muted">
                    <ActiveIcon
                      key={activeTab}
                      className="size-5 text-foreground"
                      aria-hidden
                    />
                  </div>
                </nav>
              </Tabs>
            </div>
          )}
        </div>
      </div>
    </section>
  );
};

export { Hero195 };
```
