AZMARA PLATFORM
Examples

Dashboard shell

A navigation list, a top bar with a user menu, stat cards with a loading state, and tabs, laid out with the grid.

View as Markdown for coding assistants, or see llms.txt.

The frame most admin screens share. It is the part to copy first, because every page of an app goes inside it.

Preview theme
Preview density

Overview

Revenue

$48,200

+12%
Customers

1,284

+38
Open invoices

17

+4
Churn

1.9%

-0.3%

Figures are up to date

x
x
<div className="overflow-hidden rounded-lg border border-border bg-background">
  <div className="grid md:grid-cols-[13rem_1fr]">
    <nav
      aria-label="Dashboard"
      className="border-b border-border bg-muted/40 p-3 md:border-r md:border-b-0"
    >
      <ul className="m-0 flex list-none flex-row gap-1 p-0 md:flex-col">
        {NAV.map((item) => (
          <li key={item.id}>
            <a
              href={`#${item.id}`}
              aria-current={page === item.id ? "page" : undefined}
              onClick={(event) => {
                event.preventDefault();
                setPage(item.id);
              }}
              className="flex items-center gap-2 rounded-md px-3 py-2 text-sm text-foreground hover:bg-accent aria-[current=page]:bg-accent aria-[current=page]:font-medium"
            >
              <Icon icon={item.icon} />
              {item.label}
            </a>
          </li>
        ))}
      </ul>
    </nav>

    <section aria-label={current?.label} className="flex min-w-0 flex-col gap-5 p-5">
      <div className="flex flex-wrap items-center justify-between gap-3">
        <Breadcrumbs
          label="You are here"
          items={[{ label: "Acme", href: "#acme" }, { label: current?.label ?? "" }]}
        />
        <div className="flex items-center gap-2">
          <Button
            variant="outline"
            size="sm"
            startIcon={<Icon icon={RefreshCw} />}
            loading={loading}
            loadingText="Refreshing"
            onClick={() => setLoading(true)}
          >
            Refresh
          </Button>
          <DropdownMenu>
            <DropdownMenuTrigger
              render={
                <button type="button" className="rounded-full">
                  <Avatar name="Aroha Ngata" size="sm" />
                </button>
              }
            />
            <DropdownMenuContent>
              {/* A label has to sit inside a group, which is also how it is announced. */}
              <DropdownMenuGroup>
                <DropdownMenuLabel>aroha@example.co.nz</DropdownMenuLabel>
                <DropdownMenuItem>Profile</DropdownMenuItem>
                <DropdownMenuItem>Sign out</DropdownMenuItem>
              </DropdownMenuGroup>
            </DropdownMenuContent>
          </DropdownMenu>
        </div>
      </div>

      <h2 className="m-0 text-xl font-semibold">{current?.label}</h2>

      <Grid minItemWidth="9rem" gap={4} aria-busy={loading}>
        {STATS.map((stat) => (
          <Card key={stat.label}>
            <CardHeader>
              <CardDescription>{stat.label}</CardDescription>
              {loading ? (
                <Skeleton className="h-7 w-24" />
              ) : (
                <CardTitle className="text-2xl">{stat.value}</CardTitle>
              )}
            </CardHeader>
            <CardContent>
              {!loading && <Badge variant={stat.tone}>{stat.change}</Badge>}
            </CardContent>
          </Card>
        ))}
      </Grid>
      <p className="sr-only" aria-live="polite">
        {loading ? "Refreshing figures" : "Figures are up to date"}
      </p>

      <Tabs defaultValue="usage">
        <TabsList aria-label="Details">
          <TabsTrigger value="usage">Usage</TabsTrigger>
          <TabsTrigger value="activity">Activity</TabsTrigger>
        </TabsList>
        <TabsContent value="usage" className="flex max-w-md flex-col gap-4 py-4">
          <Progress value={72} showValue aria-label="Storage used" />
          <Progress value={91} tone="warning" aria-label="Seats used" />
        </TabsContent>
        <TabsContent value="activity" className="py-4">
          <ul className="m-0 flex list-none flex-col gap-2 p-0 text-sm">
            {ACTIVITY.map((line) => (
              <li key={line}>{line}</li>
            ))}
          </ul>
        </TabsContent>
      </Tabs>
    </section>
  </div>
</div>
Open as text

What it shows

  • Landmarks. The navigation is a nav with a label and marks the current page with aria-current="page". The content is a labelled section, so a screen reader user can jump straight to it. The example does not use a main element, because this page already has one; in an app, make the content area your main.
  • A responsive layout. The navigation is a row on a narrow screen and a column from the md breakpoint, with the content filling the rest. See Layout for Grid, which also sizes the stat cards (minItemWidth).
  • A trail. Breadcrumbs say where the page sits. The last item is always the current page, so it is not a link.
  • A user menu on an avatar. The account button is named by the Avatar inside it, so it is announced with the person's name rather than with a label that ignores the initials a speech-input user can see. The menu is the standard dropdown.
  • Loading without layout shift. Refresh swaps each figure for a Skeleton of about the same size and sets aria-busy on the grid, and a visually hidden live region says "Refreshing figures" and "Figures are up to date".
  • Tabs for related detail. Tabs with arrow-key navigation, and Progress bars with names.

Limits

The links use # addresses and a state variable for the current page. In a real app, use your router's link component, set aria-current from the route, and replace the figures with data.