Web InnoventixFreeCode

App Mockup Hero

Original · free

hero with a CSS app mockup

byWeb InnoventixReact + Tailwind
heroxappmockupheroes
Open

Copy prompt gives Claude Code, Cursor or v0 a ready-to-paste prompt that recreates this exact component.

npx shadcn@latest add https://webinnoventix.com/r/herox-app-mockup.json
herox-app-mockup.tsx
"use client";

import { useRef, useState, type KeyboardEvent } from "react";
import { motion, useReducedMotion } from "motion/react";

type TabId = "overview" | "analytics" | "tasks";

interface Tab {
  id: TabId;
  label: string;
}

interface TaskItem {
  id: string;
  label: string;
  meta: string;
  done: boolean;
}

const TABS: Tab[] = [
  { id: "overview", label: "Overview" },
  { id: "analytics", label: "Analytics" },
  { id: "tasks", label: "Tasks" },
];

const WEEK_BARS: { day: string; value: number }[] = [
  { day: "M", value: 52 },
  { day: "T", value: 74 },
  { day: "W", value: 46 },
  { day: "T", value: 88 },
  { day: "F", value: 63 },
  { day: "S", value: 34 },
  { day: "S", value: 71 },
];

const INITIAL_TASKS: TaskItem[] = [
  { id: "t1", label: "Finalize Q3 launch checklist", meta: "Due today · Priya", done: true },
  { id: "t2", label: "Review onboarding copy v4", meta: "Due today · You", done: false },
  { id: "t3", label: "Ship billing retry logic", meta: "Tomorrow · Marcus", done: false },
  { id: "t4", label: "Publish changelog for 2.0", meta: "Fri · Ada", done: false },
];

export default function HeroxAppMockup() {
  const prefersReduced = useReducedMotion();
  const [activeTab, setActiveTab] = useState<TabId>("overview");
  const [tasks, setTasks] = useState<TaskItem[]>(INITIAL_TASKS);
  const tabRefs = useRef<Array<HTMLButtonElement | null>>([]);

  const doneCount = tasks.filter((t) => t.done).length;
  const donePct = Math.round((doneCount / tasks.length) * 100);

  const toggleTask = (id: string) => {
    setTasks((prev) =>
      prev.map((t) => (t.id === id ? { ...t, done: !t.done } : t)),
    );
  };

  const onTabKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {
    const current = TABS.findIndex((t) => t.id === activeTab);
    let next = current;
    if (e.key === "ArrowRight" || e.key === "ArrowDown") next = (current + 1) % TABS.length;
    else if (e.key === "ArrowLeft" || e.key === "ArrowUp") next = (current - 1 + TABS.length) % TABS.length;
    else if (e.key === "Home") next = 0;
    else if (e.key === "End") next = TABS.length - 1;
    else return;
    e.preventDefault();
    setActiveTab(TABS[next].id);
    tabRefs.current[next]?.focus();
  };

  const reveal = (delay: number) =>
    prefersReduced
      ? { initial: { opacity: 1 }, animate: { opacity: 1 } }
      : {
          initial: { opacity: 0, y: 22 },
          animate: { opacity: 1, y: 0 },
          transition: { duration: 0.6, delay, ease: [0.16, 1, 0.3, 1] as const },
        };

  return (
    <section className="relative w-full overflow-hidden bg-gradient-to-b from-slate-50 via-white to-slate-100 px-6 py-24 sm:py-28 lg:py-32 dark:from-slate-950 dark:via-slate-950 dark:to-black">
      <style>{styles}</style>

      {/* Atmosphere */}
      <div aria-hidden="true" className="pointer-events-none absolute inset-0 overflow-hidden">
        <div className="hax-blob absolute -left-24 -top-24 h-[28rem] w-[28rem] rounded-full bg-violet-400/25 blur-3xl dark:bg-violet-600/20" />
        <div className="hax-blob-slow absolute -right-20 top-1/3 h-[26rem] w-[26rem] rounded-full bg-indigo-400/20 blur-3xl dark:bg-indigo-600/20" />
        <div className="hax-blob absolute bottom-0 left-1/3 h-72 w-72 rounded-full bg-sky-300/20 blur-3xl dark:bg-sky-700/10" />
        <div className="absolute inset-0 bg-[radial-gradient(circle_at_1px_1px,rgba(15,23,42,0.05)_1px,transparent_0)] bg-[length:22px_22px] dark:bg-[radial-gradient(circle_at_1px_1px,rgba(255,255,255,0.05)_1px,transparent_0)]" />
      </div>

      <div className="relative mx-auto grid max-w-7xl items-center gap-16 lg:grid-cols-[1.05fr_1.15fr] lg:gap-12">
        {/* Copy column */}
        <div className="max-w-xl">
          <motion.a
            href="#changelog"
            {...reveal(0)}
            className="group inline-flex items-center gap-2 rounded-full border border-slate-200 bg-white/70 px-3.5 py-1.5 text-xs font-medium text-slate-600 backdrop-blur transition-colors hover:border-violet-300 hover:text-violet-700 dark:border-slate-800 dark:bg-slate-900/60 dark:text-slate-300 dark:hover:border-violet-700 dark:hover:text-violet-300"
          >
            <span className="relative flex h-2 w-2">
              <span className="hax-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75" />
              <span className="relative inline-flex h-2 w-2 rounded-full bg-emerald-500" />
            </span>
            Beacon 2.0 is live
            <svg viewBox="0 0 16 16" className="h-3.5 w-3.5 transition-transform group-hover:translate-x-0.5" fill="none" aria-hidden="true">
              <path d="M6 3.5 10.5 8 6 12.5" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
          </motion.a>

          <motion.h1
            {...reveal(0.08)}
            className="mt-6 text-4xl font-semibold leading-[1.05] tracking-tight text-slate-900 sm:text-5xl lg:text-6xl dark:text-white"
          >
            Turn scattered work into{" "}
            <span className="relative whitespace-nowrap">
              <span className="bg-gradient-to-r from-indigo-600 via-violet-600 to-sky-500 bg-clip-text text-transparent dark:from-indigo-400 dark:via-violet-400 dark:to-sky-400">
                real momentum
              </span>
              <svg viewBox="0 0 300 12" className="absolute -bottom-1 left-0 h-2.5 w-full text-violet-400/70 dark:text-violet-500/60" fill="none" aria-hidden="true" preserveAspectRatio="none">
                <path d="M2 8C60 3 240 3 298 8" stroke="currentColor" strokeWidth="3" strokeLinecap="round" />
              </svg>
            </span>
          </motion.h1>

          <motion.p
            {...reveal(0.16)}
            className="mt-6 text-lg leading-relaxed text-slate-600 dark:text-slate-400"
          >
            Beacon pulls tasks, metrics, and updates into one calm workspace. Every project gets a clear owner, a live status, and an obvious next step — so you can retire the status meeting that could have been a dashboard.
          </motion.p>

          <motion.div {...reveal(0.24)} className="mt-8 flex flex-col gap-3 sm:flex-row sm:items-center">
            <a
              href="#start"
              className="inline-flex items-center justify-center gap-2 rounded-xl bg-slate-900 px-6 py-3.5 text-sm font-semibold text-white shadow-lg shadow-slate-900/20 transition-all hover:bg-slate-800 hover:shadow-xl focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-violet-500 dark:bg-white dark:text-slate-900 dark:shadow-black/40 dark:hover:bg-slate-100"
            >
              Start free for 14 days
              <svg viewBox="0 0 16 16" className="h-4 w-4" fill="none" aria-hidden="true">
                <path d="M3 8h10M9 4l4 4-4 4" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
              </svg>
            </a>
            <a
              href="#tour"
              className="group inline-flex items-center justify-center gap-2.5 rounded-xl border border-slate-300 bg-white/70 px-6 py-3.5 text-sm font-semibold text-slate-700 backdrop-blur transition-colors hover:border-slate-400 hover:bg-white focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-violet-500 dark:border-slate-700 dark:bg-slate-900/50 dark:text-slate-200 dark:hover:border-slate-600 dark:hover:bg-slate-900"
            >
              <span className="flex h-6 w-6 items-center justify-center rounded-full bg-violet-100 text-violet-700 transition-colors group-hover:bg-violet-200 dark:bg-violet-500/20 dark:text-violet-300">
                <svg viewBox="0 0 16 16" className="h-3 w-3" fill="currentColor" aria-hidden="true">
                  <path d="M5 3.5v9l7-4.5-7-4.5Z" />
                </svg>
              </span>
              Watch 2-min tour
            </a>
          </motion.div>

          <motion.dl {...reveal(0.32)} className="mt-10 grid max-w-md grid-cols-3 gap-6 border-t border-slate-200 pt-8 dark:border-slate-800">
            {[
              { v: "3.2×", l: "faster status updates" },
              { v: "40%", l: "fewer sync meetings" },
              { v: "99.98%", l: "platform uptime" },
            ].map((s) => (
              <div key={s.l}>
                <dt className="text-2xl font-semibold tracking-tight text-slate-900 dark:text-white">{s.v}</dt>
                <dd className="mt-1 text-xs leading-snug text-slate-500 dark:text-slate-500">{s.l}</dd>
              </div>
            ))}
          </motion.dl>
        </div>

        {/* App mockup column */}
        <motion.div {...reveal(0.2)} className="relative">
          <div
            aria-hidden="true"
            className="absolute -inset-4 -z-10 rounded-[2rem] bg-gradient-to-tr from-violet-500/15 via-indigo-500/10 to-sky-500/15 blur-2xl"
          />

          {/* Window frame */}
          <div className="hax-tilt overflow-hidden rounded-2xl border border-slate-200/80 bg-white shadow-2xl shadow-slate-900/15 ring-1 ring-black/5 dark:border-slate-800 dark:bg-slate-900 dark:shadow-black/50 dark:ring-white/5">
            {/* Title bar */}
            <div className="flex items-center gap-3 border-b border-slate-200 bg-slate-50/80 px-4 py-3 dark:border-slate-800 dark:bg-slate-900/80">
              <div className="flex gap-1.5">
                <span className="h-3 w-3 rounded-full bg-rose-400" />
                <span className="h-3 w-3 rounded-full bg-amber-400" />
                <span className="h-3 w-3 rounded-full bg-emerald-400" />
              </div>
              <div className="ml-2 flex flex-1 items-center gap-2 rounded-md bg-white px-3 py-1.5 text-[11px] text-slate-400 ring-1 ring-slate-200 dark:bg-slate-950 dark:text-slate-500 dark:ring-slate-800">
                <svg viewBox="0 0 16 16" className="h-3 w-3 text-emerald-500" fill="none" aria-hidden="true">
                  <path d="M11 6.5V5a3 3 0 0 0-6 0v1.5M4 6.5h8v6H4v-6Z" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round" />
                </svg>
                app.beacon.example / workspace
              </div>
            </div>

            {/* App body */}
            <div className="flex">
              {/* Sidebar */}
              <nav aria-label="Workspace" className="hidden w-44 shrink-0 flex-col gap-1 border-r border-slate-200 bg-slate-50/50 p-3 sm:flex dark:border-slate-800 dark:bg-slate-950/40">
                <div className="mb-3 flex items-center gap-2 px-2">
                  <span className="flex h-7 w-7 items-center justify-center rounded-lg bg-gradient-to-br from-violet-600 to-indigo-600 text-white">
                    <svg viewBox="0 0 16 16" className="h-4 w-4" fill="none" aria-hidden="true">
                      <path d="M8 2v12M8 2 4 6M8 2l4 4" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
                    </svg>
                  </span>
                  <span className="text-sm font-semibold text-slate-800 dark:text-slate-100">Beacon</span>
                </div>
                {[
                  { n: "Home", icon: "M3 8l5-5 5 5M4.5 7v5h7V7" },
                  { n: "Projects", icon: "M2.5 5h4l1.2 1.5h5.8v6h-11V5Z" },
                  { n: "Insights", icon: "M3 12V7M6.5 12V4M10 12V8M13 12V6" },
                  { n: "Team", icon: "M5.5 7a2 2 0 1 0 0-4 2 2 0 0 0 0 4Zm5 0a2 2 0 1 0 0-4 2 2 0 0 0 0 4ZM2.5 12.5c0-2 1.3-3 3-3s3 1 3 3m1-3c1.7 0 3 1 3 3" },
                ].map((item, i) => (
                  <span
                    key={item.n}
                    className={`flex items-center gap-2.5 rounded-lg px-2.5 py-2 text-[13px] font-medium ${
                      i === 0
                        ? "bg-white text-slate-900 shadow-sm ring-1 ring-slate-200 dark:bg-slate-800 dark:text-white dark:ring-slate-700"
                        : "text-slate-500 dark:text-slate-400"
                    }`}
                  >
                    <svg viewBox="0 0 16 16" className="h-4 w-4" fill="none" aria-hidden="true">
                      <path d={item.icon} stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" />
                    </svg>
                    {item.n}
                  </span>
                ))}
                <div className="mt-auto rounded-lg bg-gradient-to-br from-violet-50 to-indigo-50 p-2.5 dark:from-violet-500/10 dark:to-indigo-500/10">
                  <p className="text-[11px] font-medium text-slate-700 dark:text-slate-300">Trial ends in 9 days</p>
                  <div className="mt-1.5 h-1.5 w-full overflow-hidden rounded-full bg-slate-200 dark:bg-slate-800">
                    <span className="block h-full w-2/3 rounded-full bg-gradient-to-r from-violet-500 to-indigo-500" />
                  </div>
                </div>
              </nav>

              {/* Main panel */}
              <div className="min-w-0 flex-1 p-4 sm:p-5">
                {/* Header + tabs */}
                <div className="flex items-start justify-between gap-3">
                  <div>
                    <p className="text-[11px] font-medium uppercase tracking-wider text-violet-600 dark:text-violet-400">Marketing Site Relaunch</p>
                    <h2 className="mt-0.5 text-base font-semibold text-slate-900 dark:text-white">Good afternoon, team</h2>
                  </div>
                  <div className="flex -space-x-2">
                    {["from-rose-400 to-amber-400", "from-sky-400 to-indigo-400", "from-emerald-400 to-sky-400"].map((g, i) => (
                      <span key={i} className={`h-7 w-7 rounded-full bg-gradient-to-br ${g} ring-2 ring-white dark:ring-slate-900`} />
                    ))}
                    <span className="flex h-7 w-7 items-center justify-center rounded-full bg-slate-100 text-[10px] font-semibold text-slate-500 ring-2 ring-white dark:bg-slate-800 dark:text-slate-400 dark:ring-slate-900">+6</span>
                  </div>
                </div>

                <div
                  role="tablist"
                  aria-label="Workspace views"
                  onKeyDown={onTabKeyDown}
                  className="mt-4 inline-flex gap-1 rounded-lg bg-slate-100 p-1 dark:bg-slate-800/70"
                >
                  {TABS.map((tab, i) => {
                    const selected = tab.id === activeTab;
                    return (
                      <button
                        key={tab.id}
                        ref={(el) => {
                          tabRefs.current[i] = el;
                        }}
                        role="tab"
                        id={`hax-tab-${tab.id}`}
                        aria-selected={selected}
                        aria-controls={`hax-panel-${tab.id}`}
                        tabIndex={selected ? 0 : -1}
                        onClick={() => setActiveTab(tab.id)}
                        className={`relative rounded-md px-3.5 py-1.5 text-[13px] font-medium transition-colors focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-violet-500 ${
                          selected
                            ? "bg-white text-slate-900 shadow-sm dark:bg-slate-950 dark:text-white"
                            : "text-slate-500 hover:text-slate-800 dark:text-slate-400 dark:hover:text-slate-200"
                        }`}
                      >
                        {tab.label}
                      </button>
                    );
                  })}
                </div>

                {/* Overview panel */}
                {activeTab === "overview" && (
                  <div id="hax-panel-overview" role="tabpanel" aria-labelledby="hax-tab-overview" tabIndex={0} className="mt-4 rounded-xl focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-violet-500">
                    <div className="grid grid-cols-3 gap-3">
                      {[
                        { l: "On track", v: "18", d: "+3", tone: "emerald" as const },
                        { l: "At risk", v: "4", d: "-1", tone: "amber" as const },
                        { l: "Blocked", v: "1", d: "0", tone: "rose" as const },
                      ].map((c) => (
                        <div key={c.l} className="rounded-xl border border-slate-200 bg-white p-3 dark:border-slate-800 dark:bg-slate-950/50">
                          <p className="text-[11px] text-slate-500 dark:text-slate-500">{c.l}</p>
                          <div className="mt-1 flex items-baseline gap-1.5">
                            <span className="text-xl font-semibold text-slate-900 dark:text-white">{c.v}</span>
                            <span
                              className={`text-[11px] font-medium ${
                                c.tone === "emerald"
                                  ? "text-emerald-600 dark:text-emerald-400"
                                  : c.tone === "amber"
                                    ? "text-amber-600 dark:text-amber-400"
                                    : "text-rose-600 dark:text-rose-400"
                              }`}
                            >
                              {c.d}
                            </span>
                          </div>
                        </div>
                      ))}
                    </div>

                    <div className="mt-3 rounded-xl border border-slate-200 bg-white p-4 dark:border-slate-800 dark:bg-slate-950/50">
                      <div className="flex items-center justify-between">
                        <p className="text-[13px] font-medium text-slate-700 dark:text-slate-300">Weekly throughput</p>
                        <span className="text-[11px] text-slate-400 dark:text-slate-500">tasks shipped</span>
                      </div>
                      <div className="mt-4 flex h-28 items-end gap-2.5">
                        {WEEK_BARS.map((b, i) => (
                          <div key={i} className="flex flex-1 flex-col items-center gap-1.5">
                            <div className="flex w-full flex-1 items-end">
                              <span
                                className="hax-bar w-full rounded-t-md bg-gradient-to-t from-violet-500 to-indigo-400 dark:from-violet-500 dark:to-indigo-400"
                                style={{ height: `${b.value}%`, animationDelay: `${i * 90}ms` }}
                              />
                            </div>
                            <span className="text-[10px] text-slate-400 dark:text-slate-500">{b.day}</span>
                          </div>
                        ))}
                      </div>
                    </div>
                  </div>
                )}

                {/* Analytics panel */}
                {activeTab === "analytics" && (
                  <div id="hax-panel-analytics" role="tabpanel" aria-labelledby="hax-tab-analytics" tabIndex={0} className="mt-4 rounded-xl focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-violet-500">
                    <div className="grid grid-cols-2 gap-3">
                      {[
                        { l: "Cycle time", v: "2.4d", d: "-18%" },
                        { l: "Review latency", v: "5.1h", d: "-32%" },
                      ].map((c) => (
                        <div key={c.l} className="rounded-xl border border-slate-200 bg-white p-3 dark:border-slate-800 dark:bg-slate-950/50">
                          <p className="text-[11px] text-slate-500 dark:text-slate-500">{c.l}</p>
                          <div className="mt-1 flex items-baseline gap-1.5">
                            <span className="text-xl font-semibold text-slate-900 dark:text-white">{c.v}</span>
                            <span className="text-[11px] font-medium text-emerald-600 dark:text-emerald-400">{c.d}</span>
                          </div>
                        </div>
                      ))}
                    </div>

                    <div className="mt-3 rounded-xl border border-slate-200 bg-white p-4 dark:border-slate-800 dark:bg-slate-950/50">
                      <p className="text-[13px] font-medium text-slate-700 dark:text-slate-300">Velocity trend</p>
                      <div className="mt-3">
                        <svg viewBox="0 0 320 120" className="h-32 w-full" fill="none" preserveAspectRatio="none" aria-hidden="true">
                          <defs>
                            <linearGradient id="haxArea" x1="0" y1="0" x2="0" y2="1">
                              <stop offset="0%" stopColor="rgb(139,92,246)" stopOpacity="0.35" />
                              <stop offset="100%" stopColor="rgb(139,92,246)" stopOpacity="0" />
                            </linearGradient>
                          </defs>
                          <path d="M0 90 L45 78 L90 84 L135 55 L180 62 L225 34 L270 40 L320 18 L320 120 L0 120 Z" fill="url(#haxArea)" />
                          <path className="hax-line" d="M0 90 L45 78 L90 84 L135 55 L180 62 L225 34 L270 40 L320 18" stroke="rgb(124,58,237)" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" />
                          {[[45, 78], [135, 55], [225, 34], [320, 18]].map(([x, y]) => (
                            <circle key={x} cx={x} cy={y} r="3.5" fill="white" stroke="rgb(124,58,237)" strokeWidth="2" />
                          ))}
                        </svg>
                      </div>
                      <div className="mt-2 flex justify-between text-[10px] text-slate-400 dark:text-slate-500">
                        {["W1", "W2", "W3", "W4", "W5", "W6"].map((w) => (
                          <span key={w}>{w}</span>
                        ))}
                      </div>
                    </div>
                  </div>
                )}

                {/* Tasks panel */}
                {activeTab === "tasks" && (
                  <div id="hax-panel-tasks" role="tabpanel" aria-labelledby="hax-tab-tasks" className="mt-4">
                    <div className="mb-3 flex items-center justify-between rounded-xl border border-slate-200 bg-white px-4 py-2.5 dark:border-slate-800 dark:bg-slate-950/50">
                      <p className="text-[13px] font-medium text-slate-700 dark:text-slate-300">
                        {doneCount} of {tasks.length} done
                      </p>
                      <div className="flex items-center gap-2">
                        <div className="h-1.5 w-24 overflow-hidden rounded-full bg-slate-200 dark:bg-slate-800">
                          <span
                            className="block h-full rounded-full bg-gradient-to-r from-emerald-500 to-sky-400 transition-[width] duration-500 ease-out"
                            style={{ width: `${donePct}%` }}
                          />
                        </div>
                        <span className="text-[11px] font-medium tabular-nums text-slate-500 dark:text-slate-400">{donePct}%</span>
                      </div>
                    </div>

                    <ul className="space-y-2">
                      {tasks.map((task) => (
                        <li key={task.id}>
                          <button
                            type="button"
                            role="checkbox"
                            aria-checked={task.done}
                            aria-label={task.label}
                            onClick={() => toggleTask(task.id)}
                            className="flex w-full items-center gap-3 rounded-xl border border-slate-200 bg-white px-3.5 py-2.5 text-left transition-colors hover:border-slate-300 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-violet-500 dark:border-slate-800 dark:bg-slate-950/50 dark:hover:border-slate-700"
                          >
                            <span
                              className={`flex h-5 w-5 shrink-0 items-center justify-center rounded-md border transition-colors ${
                                task.done
                                  ? "border-emerald-500 bg-emerald-500 text-white"
                                  : "border-slate-300 bg-transparent dark:border-slate-600"
                              }`}
                            >
                              {task.done && (
                                <svg viewBox="0 0 16 16" className="h-3.5 w-3.5" fill="none" aria-hidden="true">
                                  <path d="M3.5 8.5 6.5 11.5 12.5 4.5" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
                                </svg>
                              )}
                            </span>
                            <span className="min-w-0 flex-1">
                              <span
                                className={`block truncate text-[13px] font-medium ${
                                  task.done
                                    ? "text-slate-400 line-through dark:text-slate-600"
                                    : "text-slate-800 dark:text-slate-200"
                                }`}
                              >
                                {task.label}
                              </span>
                              <span className="block truncate text-[11px] text-slate-400 dark:text-slate-500">{task.meta}</span>
                            </span>
                          </button>
                        </li>
                      ))}
                    </ul>
                  </div>
                )}
              </div>
            </div>
          </div>

          {/* Floating activity toast */}
          <div className="hax-float absolute -bottom-5 -left-4 hidden items-center gap-3 rounded-xl border border-slate-200 bg-white/90 px-3.5 py-2.5 shadow-xl shadow-slate-900/10 backdrop-blur sm:flex dark:border-slate-800 dark:bg-slate-900/90 dark:shadow-black/40">
            <span className="flex h-8 w-8 items-center justify-center rounded-lg bg-emerald-100 text-emerald-600 dark:bg-emerald-500/20 dark:text-emerald-400">
              <svg viewBox="0 0 16 16" className="h-4 w-4" fill="none" aria-hidden="true">
                <path d="M3.5 8.5 6.5 11.5 12.5 4.5" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
              </svg>
            </span>
            <div>
              <p className="text-[12px] font-semibold text-slate-800 dark:text-slate-100">Ada shipped “Q3 launch”</p>
              <p className="text-[11px] text-slate-500 dark:text-slate-400">Moved to Done · just now</p>
            </div>
          </div>

          {/* Floating metric chip */}
          <div className="hax-float-slow absolute -right-3 -top-5 hidden items-center gap-2.5 rounded-xl border border-slate-200 bg-white/90 px-3.5 py-2.5 shadow-xl shadow-slate-900/10 backdrop-blur md:flex dark:border-slate-800 dark:bg-slate-900/90 dark:shadow-black/40">
            <span className="relative flex h-2.5 w-2.5">
              <span className="hax-ping absolute inline-flex h-full w-full rounded-full bg-violet-400 opacity-75" />
              <span className="relative inline-flex h-2.5 w-2.5 rounded-full bg-violet-500" />
            </span>
            <div>
              <p className="text-[11px] text-slate-500 dark:text-slate-400">Sprint burndown</p>
              <p className="text-[13px] font-semibold text-slate-800 dark:text-slate-100">On pace · 92%</p>
            </div>
          </div>
        </motion.div>
      </div>

      <style>{`
        @media (prefers-reduced-motion: reduce) {
          .hax-blob, .hax-blob-slow, .hax-bar, .hax-float, .hax-float-slow,
          .hax-ping, .hax-line, .hax-tilt {
            animation: none !important;
          }
        }
      `}</style>
    </section>
  );
}

const styles = `
  @keyframes hax-grow {
    from { transform: scaleY(0); opacity: 0; }
    to { transform: scaleY(1); opacity: 1; }
  }
  @keyframes hax-float-y {
    0%, 100% { transform: translateY(0); }
    50% { transform: translateY(-9px); }
  }
  @keyframes hax-float-y-2 {
    0%, 100% { transform: translateY(0); }
    50% { transform: translateY(7px); }
  }
  @keyframes hax-blob-move {
    0%, 100% { transform: translate(0, 0) scale(1); }
    50% { transform: translate(24px, -18px) scale(1.08); }
  }
  @keyframes hax-blob-move-2 {
    0%, 100% { transform: translate(0, 0) scale(1); }
    50% { transform: translate(-22px, 20px) scale(1.05); }
  }
  @keyframes hax-ping-out {
    75%, 100% { transform: scale(2.1); opacity: 0; }
  }
  @keyframes hax-draw {
    from { stroke-dashoffset: 520; }
    to { stroke-dashoffset: 0; }
  }
  .hax-bar {
    transform-origin: bottom;
    animation: hax-grow 0.7s cubic-bezier(0.16, 1, 0.3, 1) both;
  }
  .hax-float { animation: hax-float-y 5s ease-in-out infinite; }
  .hax-float-slow { animation: hax-float-y-2 6.5s ease-in-out infinite; }
  .hax-blob { animation: hax-blob-move 16s ease-in-out infinite; }
  .hax-blob-slow { animation: hax-blob-move-2 20s ease-in-out infinite; }
  .hax-ping { animation: hax-ping-out 1.8s cubic-bezier(0, 0, 0.2, 1) infinite; }
  .hax-line { stroke-dasharray: 520; animation: hax-draw 1.6s ease-out forwards; }
`;

Dependencies

motion

Licence

Built by Web Innoventix. Free for personal and commercial use, no attribution required.

Built by Web Innoventix

Need a custom interface, a full website, or SEO that gets you cited by AI? We design, build and rank it end to end.

Get a free quote

Similar components

Browse all →
Spotlight Hero

Spotlight Hero

Original

A centred hero with a soft radial spotlight, badge and dual call-to-action.

Split Hero

Split Hero

Original

A two-column hero pairing a headline and CTAs with a product mock and social proof.

Gradient Spotlight Hero

Gradient Spotlight Hero

Original

A minimal centred hero with a soft gradient-mesh backdrop, announcement pill and dual call-to-action buttons.

App Preview Hero

App Preview Hero

Original

A centred hero that pairs headline copy with a realistic product dashboard mock built entirely from markup, complete with browser chrome and a floating notification card.

Waitlist Capture Hero

Waitlist Capture Hero

Original

A dark, focused hero with an inline email capture form and avatar social proof, ready for pre-launch waitlists.

Image Backdrop Hero

Image Backdrop Hero

Original

A cinematic full-bleed hero with a layered image-style backdrop, overlaid left-aligned copy and a trusted-by logos strip.

Gradient Mesh Hero with Staggered Text Reveal

Gradient Mesh Hero with Staggered Text Reveal

Original

A full-screen hero pairing a drifting animated gradient-mesh backdrop with a word-by-word staggered blur-in headline and a logo marquee under the fold.

Typewriter Rotating Words Hero

Typewriter Rotating Words Hero

Original

A hero whose headline cycles through rotating words with a live typewriter caret over an animated grid backdrop, degrading to a gentle word swap when reduced motion is on.

Floating UI Cards Hero with Mouse Parallax

Floating UI Cards Hero with Mouse Parallax

Original

A hero with glassy floating UI cards that drift continuously and shift on mouse-parallax depth around a staggered centre headline.

Aurora Hero with Shimmer CTA and Logo Marquee

Aurora Hero with Shimmer CTA and Logo Marquee

Original

A dark hero with animated aurora light beams, a shimmering sweep across the primary CTA, and dual-direction logo marquees beneath the fold.

Gradient Conversion Hero

Gradient Conversion Hero

MIT

Centered, full-screen marketing hero with a colour-accent headline word, supporting copy, and dual primary/secondary CTA buttons. Dark-mode ready and dependency-free.

Split Showcase Hero

Split Showcase Hero

MIT

Two-column hero on a dark background with a headline, paragraph, and two buttons beside a gradient media panel. Responsive column stack on mobile.