Patterns · AhaSlides surfaces
Screen heading
A product page header — a title/greeting or a breadcrumb trail on the left, action buttons on the right, responsive across desktop / tablet / phone.
Examples
Title
Highlight
Breadcrumb trail
Description
Device
Product page header · title left (greeting or breadcrumb trail) · actions right
<!-- Paste-and-run: save as .html and open in a browser. No build step.
<aha-screen-heading> is the SAME shared custom element React and Vue consume — here in its
native form. The page title reuses <aha-breadcrumb size="page-title"> (plain title or `›` trail);
the actions are slotted <aha-button>s. Theming comes only from the --aha-* tokens in tokens.css. -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/tokens.css">
<script type="module">
import 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/aha-screen-heading.js'; // registers <aha-screen-heading> (+ <aha-breadcrumb>)
import 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/aha-button.js'; // registers <aha-button> for the slotted actions
import 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/icons.js'; // registers <aha-icon> for the button glyph
</script>
<!-- A greeting with a brand-accent highlight + right-hand actions (buttons slotted in). -->
<aha-screen-heading title="Welcome, Brian!" highlight="Brian" description="Here's what's happening across your workspace today.">
<aha-button slot="actions" variant="secondary">Import</aha-button>
<aha-button slot="actions" variant="primary">
<span slot="icon"><aha-icon name="system-plus" size="16" decorative></aha-icon></span>
New presentation
</aha-button>
</aha-screen-heading>
<!-- A sub-page header: pass a `breadcrumb` JSON array and the `›` trail renders as the title. -->
<aha-screen-heading breadcrumb='[{"label":"Presentations","href":"/p"},{"label":"Team offsite","href":"/p/1"},{"label":"Editor"}]'>
<aha-button slot="actions" variant="primary">Present</aha-button>
</aha-screen-heading>
import '@ahaslides-product/design/aha-screen-heading'; // registers <aha-screen-heading> (+ <aha-breadcrumb>)
import '@ahaslides-product/design/aha-button'; // registers <aha-button> for the slotted actions
import '@ahaslides-product/design/icons'; // registers <aha-icon> for the button glyph
// Attribute-driven — React 18/19 render the element directly. `breadcrumb` is a JSON array,
// so serialise it to the attribute; the title trail is the reused <aha-breadcrumb>.
function AhaScreenHeading({ title, highlight, breadcrumb, description, device, children }) {
return (
<aha-screen-heading
{...(title ? { title } : {})}
{...(highlight ? { highlight } : {})}
{...(breadcrumb ? { breadcrumb: JSON.stringify(breadcrumb) } : {})}
{...(description ? { description } : {})}
{...(device ? { device } : {})}
>
{children}
</aha-screen-heading>
);
}
// usage — a greeting header with slotted action buttons
export function DashboardHeader({ user }) {
return (
<AhaScreenHeading title={`Welcome, ${user.name}!`} highlight={user.name}
description="Here's what's happening across your workspace today.">
<aha-button slot="actions" variant="secondary">Import</aha-button>
<aha-button slot="actions" variant="primary">
<span slot="icon"><aha-icon name="system-plus" size={16} decorative /></span>
New presentation
</aha-button>
</AhaScreenHeading>
);
}
// main.ts — register the elements + mark aha-* as custom elements
import '@ahaslides-product/design/aha-screen-heading'; // registers <aha-screen-heading> (+ <aha-breadcrumb>)
import '@ahaslides-product/design/aha-button'; // registers <aha-button> for the slotted actions
import '@ahaslides-product/design/icons'; // registers <aha-icon> for the button glyph
app.config.compilerOptions.isCustomElement = (tag) => tag.startsWith('aha-');
// Component.vue — Vue 3 binds the same <aha-screen-heading> natively.
<script setup>
defineProps({ user: Object });
</script>
<template>
<!-- A greeting header: brand-accent highlight + right-hand actions (slotted <aha-button>s). -->
<aha-screen-heading
:title="`Welcome, ${user.name}!`"
:highlight="user.name"
description="Here's what's happening across your workspace today.">
<aha-button slot="actions" variant="secondary">Import</aha-button>
<aha-button slot="actions" variant="primary">
<span slot="icon"><aha-icon name="system-plus" :size="16" decorative /></span>
New presentation
</aha-button>
</aha-screen-heading>
<!-- A sub-page header: bind a `breadcrumb` JSON array → the `›` trail renders as the title. -->
<aha-screen-heading
:breadcrumb='JSON.stringify([{label:"Presentations",href:"/p"},{label:"Team offsite",href:"/p/1"},{label:"Editor"}])'>
<aha-button slot="actions" variant="primary">Present</aha-button>
</aha-screen-heading>
</template>
API
| Prop | Type | Default | Notes |
|---|---|---|---|
title | string | — | The page title — rendered via <aha-breadcrumb size="page-title"> (Heading4 24/600, text-default), unless `highlight` makes it an accent greeting |
highlight | string | — | Optional substring of `title` rendered in color-primary — e.g. the person's name in a greeting |
breadcrumb | JSON [{label, href?}] | — | When present, a `›` trail renders as the page title via the reused <aha-breadcrumb size="page-title"> (for a sub-page) |
description | string | — | Optional subtitle under the title (14px, text-secondary) |
device | 'desktop' | 'tablet' | 'phone' | desktop | Deterministic responsive layout — phone wraps the actions below the title |
Install
# .npmrc — once: point the @ahaslides-product scope at GitHub Packages
@ahaslides-product:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN} # a GitHub token with read:packages
npm i @ahaslides-product/design
import '@ahaslides-product/design/tokens.css'; // once, at the app root
import '@ahaslides-product/design/aha-screen-heading'; // registers <aha-screen-heading>
Agent feed for this component (absolute, fetchable anywhere): screen-heading.agent.json · screen-heading.md · screen-heading.llms.txt
When to use
When to use
- Screen heading — the header row of a product page — a title/greeting or a hierarchy trail plus the page's primary actions
- Breadcrumb — only the ancestor trail / page title is needed, with no right-hand actions (use <aha-breadcrumb size="page-title"> directly — it IS the title this header wraps)
- Card — a titled content container, not the page-level header
One primary action on the right at most; the rest secondary. Use a plain `title` for a top-level page (optionally with a `highlight` name), and a `breadcrumb` trail for a sub-page — both render the page heading via the reused <aha-breadcrumb size="page-title">, never a hand-rolled <h1>. Keep the title a short sentence-case phrase.
Surfaces
dashboard editor admin settings
Spec
Type title = <aha-breadcrumb size="page-title"> — Heading4 24 / SemiBold 600 / line-height 1.3 / #1A1A1A (text-default) for a single-crumb page title; 18/600 with an ancestor path · Highlight optional `highlight` substring of the title in color-primary #6A1EBB (a person's name) → a local greeting <h1>, matched to the breadcrumb page-title solo · Breadcrumb `breadcrumb` JSON [{label, href?}] → the `›` trail renders as the page title via the reused <aha-breadcrumb size="page-title"> (heading-level 1) · Description optional subtitle, Plus Jakarta 14/22 · text-secondary #4A4A4A, under the title · Actions slot="actions" — the consumer drops <aha-button>s here (never a hand-rolled button) · Gap 16 between the title area and the actions · 8 title→description and between action buttons · Layout desktop / tablet: title left, actions right on one row · phone: actions wrap below the title