Aura Design System

App Bar

A top bar in three sizes that gains a shadow when content scrolls under it.

Preview

Loading...
import * as React from "react";
import { BellIcon } from "@radix-ui/react-icons";
import { AppBar } from "@/components/ui/AppBar";

export function AppBarDemo() {
  return (
    <div className="overflow-hidden rounded-sm border border-gray-6">
      <AppBar size="small" title="Inbox">
        <button
          type="button"
          aria-label="Notifications"
          className="inline-flex size-3 items-center justify-center rounded-sm hover:bg-gray-3"
        >
          <BellIcon className="icon" />
        </button>
      </AppBar>
    </div>
  );
}

Installation

Make sure that namespace is set in your component.json file. Namespace docs: Learn more about namespaces

pnpm dlx shadcn@latest add @aura/app-bar

Manual

Install the following dependencies:

pnpm install class-variance-authority

Copy and paste the class names utility into your utils/class-names.ts file.

import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}

Copy and paste the AppBar component into your components/ui/AppBar.tsx file.

"use client";

import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/utils/class-names";

const appBarVariants = cva(
  "sticky top-0 z-30 flex items-center gap-1 bg-gray-1 px-1.5",
  {
    variants: {
      size: {
        small: "h-4",
        medium: "h-6",
        large: "h-8 items-end pb-1",
      },
    },
    defaultVariants: {
      size: "small",
    },
  },
);

function AppBar({
  className,
  size,
  elevated = false,
  title,
  children,
  ...props
}: React.ComponentProps<"header"> &
  VariantProps<typeof appBarVariants> & {
    elevated?: boolean;
    title: string;
  }) {
  return (
    <header
      data-slot="app-bar"
      data-size={size ?? "small"}
      data-elevated={elevated ? "true" : "false"}
      className={cn(appBarVariants({ size }), elevated && "shadow-md", className)}
      {...props}
    >
      <p className={cn("m-0 font-medium", size === "large" ? "h5" : "h6")}>{title}</p>
      <div className="ml-auto flex items-center gap-0.5">{children}</div>
    </header>
  );
}

export { AppBar, appBarVariants };

Usage

Medium

export const Medium = () => {
  return (
    <div className="overflow-hidden rounded-sm border border-gray-6">
      <AppBar size="medium" title="Inbox" />
    </div>
  );
};

Large

export const Large = () => {
  const [elevated, setElevated] = React.useState(true);
  return (
    <div
      className="h-24 overflow-auto rounded-sm border border-gray-6"
      onScroll={(event) => setElevated(event.currentTarget.scrollTop > 0)}
    >
      <AppBar size="large" elevated={elevated} title="Inbox" />
      <div className="space-y-1 p-1.5">
        <p className="m-0">Scroll this panel. The bar picks up a shadow once content moves underneath it.</p>
        <p className="m-0">A second line keeps the preview tall enough to scroll.</p>
        <p className="m-0">A third line finishes the sample.</p>
      </div>
    </div>
  );
};