# Handoff Nav: Studio at Phone Width

> An interiors studio's site in a phone frame. The links fold into a menu that grows out of the pill, and "Book a call" shares the pill with it once caught; the hero copy gets wider padding through `data-[placement=hero]:`.

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

- Page, with a live preview: https://shadcn.exchange/r/keyframeui/handoff-nav-studio-demo
- Screenshot: https://shadcn.exchange/shot/keyframeui/handoff-nav-studio-demo/light.png
- Registry item: https://keyframeui.com/r/handoff-nav-studio-demo.json
- Categories: navigation, scroll, interaction
- Listed: 2026-11-02, source last changed 2026-11-02

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/keyframeui/handoff-nav-studio-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/handoff-nav.json`

## Notes from the registry

Live preview, examples and props: https://keyframeui.com/components/handoff-nav#handoff-nav-studio-demo

## Files

### `registry/demos/handoff-nav-studio-demo.tsx`

```tsx
"use client";

import * as React from "react";

import { HandoffNav, HandoffNavCta, HandoffNavProvider } from "@/components/ui/handoff-nav";

const photo = (id: string) =>
  `https://images.unsplash.com/photo-${id}?auto=format&fit=crop&w=720&h=900&q=80`;

const work = [
  { id: "1638193399915-e22226710f2b", title: "Rua das Flores", kind: "Apartment, 92 m²", year: "2026" },
  { id: "1630232782797-7b48bf7125e4", title: "Casa Alfama", kind: "Kitchen and dining", year: "2025" },
  { id: "1633944095397-878622ebc01c", title: "Quinta Norte", kind: "Guest suite", year: "2025" },
  { id: "1633429083812-2f9c1ef8738d", title: "Atelier Graça", kind: "Reading room", year: "2024" },
];

const services = ["Whole homes", "Kitchens and joinery", "Lighting plans", "Furniture sourcing"];

export function HandoffNavStudioDemo() {
  const scrollRef = React.useRef<HTMLDivElement>(null);

  return (
    // The studio's site at phone width: the links fold into the menu, and the caught button
    // shares the pill with it.
    <div className="flex w-full justify-center">
      <div className="w-full max-w-[390px] overflow-hidden rounded-[2rem] border border-stone-300 bg-[#f6f3ee] shadow-[0_30px_60px_-30px_rgb(28_25_23/0.45)] dark:border-stone-700 dark:bg-stone-950">
        <div ref={scrollRef} className="relative h-[var(--demo-height,36rem)] overflow-y-auto overscroll-contain">
          <HandoffNavProvider>
            <HandoffNav
              containerRef={scrollRef}
              surfaceClassName="bg-[#f6f3ee]/85 dark:bg-stone-900/85"
              logo={
                <a
                  href="#"
                  className="rounded-sm font-serif text-[17px] tracking-tight text-stone-900 focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-stone-900 dark:text-stone-100 dark:focus-visible:outline-white"
                >
                  Atelier Mora
                </a>
              }
              links={[
                { label: "Work", href: "#work" },
                { label: "Studio", href: "#studio" },
                { label: "Journal", href: "#journal" },
                { label: "Contact", href: "#contact" },
              ]}
              action={{ label: "hello@ateliermora.pt", href: "#contact" }}
            />

            <main className="px-5 pb-12">
              <section className="pt-8">
                <p className="text-[13px] text-stone-500">Interiors · Lisbon</p>
                <h1 className="mt-4 font-serif text-[40px]/[1.02] tracking-[-0.02em] text-stone-900 dark:text-stone-100">
                  Rooms that hold <em className="text-stone-500">still.</em>
                </h1>
                <p className="mt-5 text-[15px]/6 text-stone-600 dark:text-stone-400">
                  We design homes around the light they already have, and finish them with things made a few
                  streets away.
                </p>
                <div className="mt-7 flex items-center gap-4">
                  <HandoffNavCta
                    href="#contact"
                    className="bg-stone-900 hover:bg-stone-700 data-[placement=hero]:px-6 dark:bg-stone-100 dark:text-stone-900 dark:hover:bg-stone-300"
                  >
                    Book a call
                  </HandoffNavCta>
                  <a href="#work" className="text-sm text-stone-700 underline underline-offset-4 dark:text-stone-300">
                    See the work
                  </a>
                </div>
              </section>

              <section id="work" className="mt-12 space-y-8">
                {work.map((item) => (
                  <figure key={item.title}>
                    <div className="aspect-[4/5] overflow-hidden rounded-xl bg-stone-200 dark:bg-stone-800">
                      {/* eslint-disable-next-line @next/next/no-img-element */}
                      <img src={photo(item.id)} alt={`${item.title}, ${item.kind}`} className="size-full object-cover" />
                    </div>
                    <figcaption className="mt-3 flex items-baseline justify-between text-[13px]">
                      <span className="font-serif text-[17px] text-stone-900 dark:text-stone-100">{item.title}</span>
                      <span className="text-stone-500">
                        {item.kind} · {item.year}
                      </span>
                    </figcaption>
                  </figure>
                ))}
              </section>

              <section id="studio" className="mt-14 border-t border-stone-900/10 pt-8 dark:border-white/10">
                <h2 className="font-serif text-2xl tracking-tight text-stone-900 dark:text-stone-100">What we take on</h2>
                <ul className="mt-4 divide-y divide-stone-900/10 dark:divide-white/10">
                  {services.map((service) => (
                    <li key={service} className="py-3 text-[15px] text-stone-700 dark:text-stone-300">
                      {service}
                    </li>
                  ))}
                </ul>
              </section>

              <footer id="contact" className="mt-14 text-[13px]/6 text-stone-500">
                Rua do Benformoso 41, Lisbon
                <br />
                Two new homes a season. Next opening: March.
              </footer>
            </main>
          </HandoffNavProvider>
        </div>
      </div>
    </div>
  );
}
```
