# Footnote: Glass Over a Photo

> A trip planner's answer on a frosted card over Lisbon at dusk, in a browser frame: where to stay for two nights on foot, with walking, review, weather and transit sources.

A shadcn/ui block from the [@keyframeui](https://keyframeui.com/?utm_source=shadcn.exchange) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/keyframeui/footnote-glass-demo).

- Page, with a live preview: https://shadcn.exchange/r/keyframeui/footnote-glass-demo
- Screenshot: https://shadcn.exchange/shot/keyframeui/footnote-glass-demo/light.png
- Registry item: https://keyframeui.com/r/footnote-glass-demo.json
- Categories: ai, text, hover
- Listed: 2026-11-02, source last changed 2026-11-02

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/keyframeui/footnote-glass-demo.json
```

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

## Dependencies

- Registry items: `https://keyframeui.com/r/footnote.json`

## Notes from the registry

Live preview, examples and props: https://keyframeui.com/components/footnote#footnote-glass-demo

## Files

### `registry/demos/footnote-glass-demo.tsx`

```tsx
"use client";

import { Footnote, type FootnoteClaim, type FootnoteSource } from "@/components/ui/footnote";

const PHOTO =
  "https://images.unsplash.com/photo-1688297483354-3057315926a1?auto=format&fit=crop&w=1600&h=1100&q=80";

const sources: FootnoteSource[] = [
  {
    id: "walks",
    site: "lisbonwalks.guide",
    title: "Baixa on foot: the flat way round",
    href: "#baixa-on-foot",
    snippet:
      "Baixa is the low, level grid rebuilt after 1755. From Praça do Comércio most of the old town is within 20 minutes' walk, and you only climb when you choose to.",
    quote: "within 20 minutes' walk",
  },
  {
    id: "stays",
    site: "staynotes.app",
    title: "Alfama guesthouses: what 2,400 reviews mention",
    href: "#alfama-reviews",
    snippet:
      "Views and quiet come up most, then stairs. Guests with suitcases call the walk up from the metro the hardest part of the stay.",
    quote: "the hardest part of the stay",
  },
  {
    id: "climate",
    site: "climatenormals.org",
    title: "Lisbon: November averages",
    href: "#november-averages",
    snippet: "Daytime highs average 17°C. Rain falls on about ten days of the month, usually in short showers.",
    quote: "about ten days of the month",
  },
  {
    id: "transit",
    site: "transitatlas.io",
    title: "Tram 28: when it's quiet",
    href: "#tram-28",
    snippet: "Cars fill from about 10am until early evening. Before 9am you'll usually get a seat at Martim Moniz.",
    quote: "Before 9am you'll usually get a seat",
  },
];

const answer: FootnoteClaim[] = [
  {
    text: "Stay in Baixa: it's the flat grid between the river and the hills, and most sights are within 20 minutes on foot.",
    cite: "walks",
  },
  { text: "Alfama is prettier but steep, and with luggage the climb from the metro is the hard part.", cite: "stays" },
  { text: "November is mild, around 17°C, but expect rain on about one day in three.", cite: "climate" },
  { text: "Tram 28 is packed by 10am, so ride it early or walk the same route downhill.", cite: "transit" },
];

export function FootnoteGlassDemo() {
  return (
    <div className="@container/frame relative w-full max-w-3xl overflow-hidden rounded-[22px] bg-zinc-900 shadow-xl ring-1 ring-zinc-950/10 dark:ring-white/10">
      {/* eslint-disable-next-line @next/next/no-img-element */}
      <img
        src={PHOTO}
        alt="Lisbon's rooftops at dusk under a deep blue and orange sky"
        className="absolute inset-0 size-full object-cover"
      />
      <div className="absolute inset-0 bg-gradient-to-t from-zinc-950/35 via-transparent to-zinc-950/10" />

      <div className="relative flex h-10 items-center gap-3 border-b border-white/15 bg-white/10 px-3.5 backdrop-blur-md">
        <div className="flex gap-1.5" aria-hidden>
          <span className="size-2.5 rounded-full bg-white/45" />
          <span className="size-2.5 rounded-full bg-white/30" />
          <span className="size-2.5 rounded-full bg-white/30" />
        </div>
        <div className="mx-auto flex h-6 w-full max-w-64 items-center justify-center gap-1.5 rounded-full bg-white/15 px-3 text-[11px] text-white/85">
          <LockIcon className="size-2.5 shrink-0" />
          <span className="truncate">saunter.app/ask</span>
        </div>
        <div className="w-10" aria-hidden />
      </div>

      <div className="relative px-3 pt-40 pb-3 @[34rem]/frame:px-8 @[34rem]/frame:pt-52 @[34rem]/frame:pb-8">
        <Footnote
          question="Two nights in Lisbon in November: where should we stay to walk everywhere?"
          answer={answer}
          sources={sources}
          read={14}
          avatar={<SunMark className="size-3.5" />}
          className="max-w-[27rem] bg-white/70 shadow-2xl shadow-zinc-950/20 ring-white/60 backdrop-blur-xl dark:bg-zinc-950/60 dark:ring-white/15"
        />
      </div>
    </div>
  );
}

function SunMark({ className }: { className?: string }) {
  return (
    <svg viewBox="0 0 16 16" className={className} aria-hidden>
      <path d="M2 11.5a6 6 0 0 1 12 0Z" fill="currentColor" />
      <path d="M1.5 13.25h13" stroke="currentColor" strokeWidth={1.5} strokeLinecap="round" />
    </svg>
  );
}

function LockIcon({ className }: { className?: string }) {
  return (
    <svg viewBox="0 0 12 12" className={className} fill="none" aria-hidden>
      <rect x="2.5" y="5.25" width="7" height="5" rx="1.25" fill="currentColor" />
      <path d="M4 5.25V4a2 2 0 1 1 4 0v1.25" stroke="currentColor" strokeWidth={1.2} />
    </svg>
  );
}
```
