Skip to content

BrowserFrame

Layout

A presentation browser frame with address text and editable child content.

Product dashboard frameDark chromeLong-address truncation
Open preview

Responsive viewport — resize the window to explore. Direction and density apply only to this preview. Theme applies to the docs too.

Usage

Wrap product screenshots, dashboards, or case-study content in a browser-style frame. The address is display text rather than a real location field; the decorative chrome never navigates or requests that address. Children remain ordinary React content, with no iframe or isolation boundary. Use neutral or dark chrome to match the presentation while keeping the child content in its own theme.

Import
import { BrowserFrame } from "@/components/ui/browser-frame";

Shipped as editable source in src/components/ui/browser-frame.tsx in both apps. Copy the implementation below when moving it to another project. Copy the complete example from Source code for all imports and state. Add "use client" when using hooks or event handlers. See installation and theming for project setup.

Component source

The complete implementation is included in both apps. It uses the React, Radix, Lucide, and shared-core dependencies already installed in Apex. Keep your project’s semantic theme tokens when reusing it.

src/components/ui/browser-frame.tsx
import type { ReactNode } from "react";
import { LockKeyhole } from "lucide-react";
import { cn } from "@dashboardpack/core/lib/utils";
export interface BrowserFrameProps {
  label: string;
  address?: string;
  children: ReactNode;
  chrome?: "neutral" | "dark";
  className?: string;
}
export function BrowserFrame({
  label,
  address = "app.example.com",
  children,
  chrome = "neutral",
  className,
}: BrowserFrameProps) {
  return (
    <figure
      className={cn(
        "min-w-0 overflow-hidden rounded-xl border bg-card shadow-sm",
        className,
      )}
    >
      <div
        className={cn(
          "flex items-center gap-3 border-b px-3 py-3",
          chrome === "dark" ? "bg-zinc-900 text-white" : "bg-muted/50",
        )}
      >
        <span aria-hidden className="flex shrink-0 gap-1.5">
          <span className="size-2 rounded-full bg-rose-400" />
          <span className="size-2 rounded-full bg-amber-400" />
          <span className="size-2 rounded-full bg-emerald-400" />
        </span>
        <span
          className={cn(
            "flex min-w-0 flex-1 items-center justify-center gap-1.5 rounded-md px-2 py-1 text-[10px]",
            chrome === "dark"
              ? "bg-white/10"
              : "bg-background text-muted-foreground",
          )}
        >
          <LockKeyhole aria-hidden className="size-3 shrink-0" />
          <span className="truncate" dir="ltr">
            {address}
          </span>
        </span>
      </div>
      <figcaption className="sr-only">
        {label}. Presentation frame, address is display text.
      </figcaption>
      <div className="min-w-0">{children}</div>
    </figure>
  );
}

API reference

Common props and defaults. Slot-specific props are named below; native elements also accept their standard HTML attributes. The component TypeScript definitions are the complete type reference.

BrowserFrame props
PropType / DefaultDescription
labelstring

Default: required

Accessible presentation caption.
addressstring

Default: app.example.com

Display-only address text.
childrenReactNode

Default: required

Content inside the frame.
chromeneutral | dark

Default: neutral

Chrome appearance, independent of child content.
classNamestring

Default: —

Extend the container with semantic theme utilities.

Build with these too