Prisma
Live Preview
Default
Flight Details
Page content area...
Transparent (over hero image)
Sydney
Explore
Discover amazing places
Glass (iOS 26 Liquid Glass)
Search
Glass app bar floats over content

--- description: Hướng dẫn Agent tự động tạo UI Component App Bar — thanh điều hướng cố định ở đầu màn hình mobile app. Tích hợp trends iOS 26 Liquid Glass, Material Design 3 Expressive, Samsung OneUI 7.

App Bar Component Generation Skill

Skill này hướng dẫn bạn (AI Agent) tạo component App Bar — thanh tiêu đề + điều hướng ở đầu mỗi screen trong mobile app.

1. Mục tiêu (Objective)

Tạo mobile app bar (top bar) hỗ trợ back navigation, title, actions, collapsing large title, và tương thích iOS 26 Liquid Glass floating bars + Material Design 3 Expressive flexible app bars + Samsung OneUI 7 minimal headers.

2. AI Context & Intent (Ngữ cảnh cho AI)

Khi nào dùng App Bar?

  • Screen-level header: mỗi màn hình cần tiêu đề + back button
  • Contextual actions: 1-3 action icons (search, menu, share...)
  • Mobile-first: compact height, touch-friendly

Phân biệt với component khác

Tình huống Component đúng Lý do
Mobile screen header (back + title + actions) App Bar Compact, screen-level
Desktop horizontal nav (logo + links) navigation-menu Wide, site-level
Bottom mobile navigation Bottom Navigation Navigation ≠ header
Search-only header Search Bar Single purpose
Section header within page Section title (typography) In-flow, no sticky

Decision Tree cho AI

text
Cần header cho mobile screen?
├─ Screen title + back button → App Bar
│   ├─ Fixed trên hero image → variant="transparent"
│   ├─ Medium title + subtitle → variant="medium"
│   ├─ Large title collapse on scroll → variant="large"
│   ├─ Standard solid background → variant="default"
│   ├─ Glass/translucent → variant="glass"
│   └─ Search-focused → variant="search"
│   (Small / Medium có thể showTitle={false} khi context đủ rõ)
├─ Web desktop navigation → navigation-menu
├─ No title, just actions → Toolbar
└─ In-flow section heading → Typography heading

3. Platform Trend Research (2025-2026)

3.1. iOS 26 — Liquid Glass Navigation Bar

Feature Spec
Material Liquid Glass — translucent, floating
Height 44pt (navigation bar) + status bar (44-59pt)
Title alignment Center-aligned (default), Large title (left, collapses)
Large title Starts large (34pt), scrolls into inline (17pt)
Back button Chevron + previous screen title (auto)
Glass effect .glassEffect() modifier, floats over content
Bar buttons Glass chip shape, interactive hover/press
Grouped bars Nav bar + toolbar morph into glass bubbles
Search bar Can embed in large title area, morphs on activation
Transition Glass elements reshape contextually between screens

3.2. Material Design 3 Expressive — App Bar

Feature Spec
Name "App bar" (simplified from "Top app bar")
Variants Small, Medium flexible, Large flexible, Search
Small 64dp height, title + navigation icon + actions
Small (no title) Title hidden — chỉ nav icon + actions, dùng khi context đủ rõ
Medium flexible 112dp, larger title + subtitle, collapsible
Medium flexible (no title) Title hidden — chỉ giữ nav + actions, content area trống
Large flexible Prominent title, imagery support, filled buttons
Search variant Search field integrated, icons inside/outside
Title on/off Small & Medium có thể ẩn title tùy use case (e.g. map, media viewer)
Title align Left (default) or center
Colors Surface container, on-surface text
Elevation Scroll: 0→3dp on scroll for shadow
Actions 1-2 action icons recommended
Deprecated Old "medium" and "large" → use "flexible" versions

3.3. Samsung OneUI 7

Feature Spec
Style Clean, minimal, subtle radius
Large title Bold, left-aligned, collapses on scroll
Back button Simple arrow , no label
Actions Icon-only, right-aligned
Search Bottom-positioned search in some system apps
Glass preview (8.5) Transparency effects, frosted panels
Color Follows system dynamic color, subtle gradients

3.4. Cross-platform Convergence

Feature iOS 26 MD3 Exp OneUI 7
Height (compact) 44pt 64dp 56dp
Large title ✅ collapses ✅ flexible ✅ collapses
Glass/transparent ✅ (preview)
Center title ✅ default ✅ option
Subtitle ✅ (flexible)
Embedded search ✅ (large area) ✅ (search variant)
Back label ✅ auto

4. Ngữ nghĩa & Phân loại (Semantics)

4.1. Visual Variants

Variant Mô tả Use case Platform feel
default Solid background, shadow on scroll (= MD3 Small) Standard screens MD3 / cross-platform
medium Taller bar, larger title + subtitle (= MD3 Medium flexible) Detail screens, section landing MD3 Expressive
transparent No background, content behind Hero image overlay Cross-platform
glass Liquid glass, floating, translucent Premium / iOS-like iOS 26
large Large title, collapses on scroll (= MD3 Large flexible) Top-level screens iOS + OneUI + MD3
search Morphs title into search field Search-focused screens MD3 Expressive

Title on/off: default (Small) và medium hỗ trợ showTitle={false} — ẩn title khi context đã đủ rõ (map view, media player, camera). Actions vẫn hiển thị.

4.2. Sub-components / Slots

Part Mô tả Tokens chính
Container Full-width, fixed/sticky top --background / transparent
Leading Back button / menu icon --foreground, 44×44 touch
Title Screen title text heading-4 style
Large Title Large scrollable title heading-1 / display-small
Subtitle Secondary text below title body-small, --muted-foreground
Actions 1-3 action icon buttons --foreground, 44×44 touch
Search Field Expandable search input Reuses search component

4.3. Slot Map (Figma ↔ Code)

📎 Source: slot-manifest.jsonapp-bar · Layer: ground

Figma Slot data-slot CSS Class Required Accepts
Root app-bar .ground-appbar
Leading app-bar-leading .ground-appbar__leading back-button, menu-button, icon-button
Title app-bar-title .ground-appbar__title text, search-field
Subtitle app-bar-subtitle .ground-appbar__subtitle text
Actions app-bar-actions .ground-appbar__actions icon-button-group (max 3)
html
<!-- HTML skeleton with data-slot -->
<header class="ground-appbar" data-slot="app-bar" role="banner">
  <div class="ground-appbar__leading" data-slot="app-bar-leading">
    <button aria-label="Go back">←</button>
  </div>
  <h1 class="ground-appbar__title" data-slot="app-bar-title">Title</h1>
  <div class="ground-appbar__actions" data-slot="app-bar-actions">
    <button aria-label="More">⋯</button>
  </div>
</header>

4.4. Interactive States

State Visual Token
Resting Background transparent or solid --background
Scrolled Shadow appears, title shrinks (large) --shadow-sm
Back pressed Scale 0.92, navigate back transform: scale(0.92)
Action hover Subtle bg circle --state-layer-hover
Action focus Focus ring --primary outline
Search active Title morphs into input field --input, --input-border

4.4. Behaviors

Behavior Description
Sticky Stays at top during scroll (default)
Collapse Large title shrinks to inline on scroll
Elevation on scroll Shadow appears after scrolling past threshold
Back navigation Leading button triggers page pop / router back
Search morph Title area transforms into search input (search variant)
Status bar Content positioned below status bar (safe area)
Glass morph Glass shape adapts during screen transitions (glass variant)

5. Elevation Layer Classification

Kết luận: App Bar = Ground layer — không phải Surface.

Tại sao Ground?

App Bar là page chrome — cấu trúc cố định của trang, luôn hiển thị, không dismissable.

Tiêu chí Ground Surface App Bar
Luôn hiển thị? ❌ (tạm thời) ✅ → Ground
Overlay content? ❌ → Ground
Dismissable? ❌ → Ground
Shadow mặc định? None --shadow-lg None → Ground

Scroll Elevation — nâng elevation nhưng không đổi layer

Khi scroll, App Bar thêm --shadow-sm để báo hiệu content bên dưới bị che. Đây là visual feedback, không phải thay đổi layer.

State Background Shadow Layer
Resting (chưa scroll) --background None Ground
Scrolled (floating) --background --shadow-sm Ground + modifier

MD3 xử lý tương tự: elevation 0dp → 3dp khi scroll, nhưng app bar vẫn ở "Surface container" role (= Ground trong Prisma).

Quy tắc nhanh: Luôn hiển thị + không dismiss = Ground. Shadow on scroll = elevation modifier, không đổi layer.

Cross-platform evidence

Platform Token/Role Prisma mapping
MD3 Expressive Surface container, elevation 0→3dp Ground + --shadow-sm on scroll
Apple HIG (iOS 26) Navigation bar, opaque/glass Ground (glass = decorator)
Samsung OneUI 7 System header, no elevation Ground

6. Token Mapping

📦 Atomic Mapping: See ATOMIC-MAPPING.md for complete token spec.

📦 Atomic Mapping: UI Layer: Ground, Density Tier: — (fixed height) Transparent variant overlays content → fg may need --foreground-inverse on dark heroes.

Property Token Ghi chú
Container bg --background default variant
Container bg (transparent) transparent Hero overlay
Container bg (glass) --background + opacity + backdrop blur Glass variant (Ground layer, decorative glass)
Container fg --foreground
Container fg (transparent on dark) --foreground-inverse White on hero
Border bottom --border Optional, appears on scroll
Shadow on scroll --shadow-sm Subtle elevation
Title font heading-4 text style 18px, semibold
Large title font heading-1 text style 30px, bold
Subtitle font body-small text style 14px, normal
Subtitle fg --muted-foreground
Back icon size --icon-lg (24px)
Action icon size --icon-lg (24px)
Touch target 44×44px min --size-min-width-11
Button bg (ghost) transparent
Button hover --state-layer-hover
Height (compact) 44-56px --spacing-11 to --spacing-14
Status bar offset env(safe-area-inset-top) Or --safe-area-top
Inline padding --spacing-4 (16px) --block-padding-small
Action gap --item-inline-gap-default (8px)
Transition --motion-smooth Title collapse
z-index --z-index-fixed Above content

Glass variant tokens

Property Value Note
Backdrop blur(20px) saturate(160%) Decorative OK
Glass border 1px solid var(--border) Token-based
Floating margin var(--spacing-2) var(--spacing-4) 0 Inset
Floating radius --radius-2xl (24px) Rounded

6. Props & API

typescript
interface AppBarProps {
  /** Visual variant */
  variant?: 'default' | 'medium' | 'transparent' | 'glass' | 'large' | 'search';
  /** Screen title */
  title: string;
  /** Show/hide title — default: true. Set false for map, media, camera screens */
  showTitle?: boolean;
  /** Subtitle (medium, large variants) */
  subtitle?: string;
  /** Show back button */
  showBack?: boolean;
  /** Back button label (iOS style — default: hidden) */
  backLabel?: string;
  /** Back handler */
  onBack?: () => void;
  /** Action buttons (max 3) */
  actions?: AppBarAction[];
  /** Add shadow on scroll */
  elevateOnScroll?: boolean;
  /** Collapse large title on scroll */
  collapseOnScroll?: boolean;
}

interface AppBarAction {
  /** Icon element */
  icon: ReactNode;
  /** Accessible label */
  label: string;
  /** Click handler */
  onClick: () => void;
  /** Badge count */
  badge?: number;
}

7. Accessibility (a11y)

  • Semantic HTML: <header role="banner"> containing <nav> for actions
  • Title: Use <h1> for page title inside app bar (primary heading)
  • Back button: <button aria-label="Go back"> or <a> with aria-label
  • Actions: Each <button> has descriptive aria-label (e.g., "Open search", "More options")
  • Focus: :focus-visible ring on all interactive elements
  • Keyboard: Tab through back → title (if focusable) → actions. Escape = go back.
  • Reduced motion: @media (prefers-reduced-motion) — disable collapse animation
  • Touch target: Min 44×44px for back + actions (WCAG 2.2)
  • Contrast: Title and icons must have ≥ 4.5:1 contrast (transparent variant: check on hero bg!)
  • Landmark: App bar should be a navigation landmark

8. Best Practices & Rules

  • Max 3 actions: More → hide behind "more" menu (dropdown-menu)
  • Title clarity: Short, descriptive. Max ~20 characters.
  • Không Hardcode: colors, spacing, typography từ tokens
  • Safe area: Always offset by status bar height
  • Transparent variant: Ensure readable contrast — may need text shadow or gradient overlay
  • Large title: Only for top-level screens, not detail screens
  • Glass variant: Only with liquid/glass style showcase — never mix with flat styles
  • Dark Mode: transparent variant may need inverted colors
  • Search morph: Only search variant — don't add search to all bars

9. Example Usage

jsx
{/* Default app bar */}
<AppBar
  variant="default"
  title="Flight"
  showBack
  onBack={() => router.back()}
  actions={[
    { icon: <MoreIcon />, label: "More options", onClick: openMenu }
  ]}
  elevateOnScroll
/>

{/* Transparent over hero */}
<AppBar
  variant="transparent"
  title="Sydney"
  showBack={false}
  actions={[
    { icon: <BellIcon />, label: "Notifications", onClick: openNotifs, badge: 2 },
    { icon: <ProfileIcon />, label: "Profile", onClick: openProfile }
  ]}
/>

{/* Large title (iOS/OneUI style) */}
<AppBar
  variant="large"
  title="Boarding Pass"
  showBack
  onBack={goBack}
  collapseOnScroll
/>

{/* Glass (Liquid Glass) */}
<AppBar
  variant="glass"
  title="Search"
  actions={actions}
/>

10. CSS Skeleton

css
/* Container — Ground layer */
.ground-appbar {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: var(--z-index-fixed);
  background: var(--background);
  padding-top: env(safe-area-inset-top, var(--spacing-11));
  transition: box-shadow var(--duration-normal-1) var(--easing-standard);
}

/* Scrolled — shadow appears */
.ground-appbar--scrolled {
  box-shadow: var(--shadow-sm);
}

/* Inner layout */
.ground-appbar__inner {
  display: flex;
  align-items: center;
  height: var(--spacing-11); /* 44px compact */
  padding: 0 var(--spacing-4);
  gap: var(--spacing-2);
}

/* Back button */
.ground-appbar__back {
  width: var(--size-min-width-11); /* 44px touch */
  height: var(--size-min-width-11);
  border-radius: var(--radius-full);
  background: none;
  border: none;
  color: var(--foreground);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  margin-left: calc(-1 * var(--spacing-2));
  transition: background var(--duration-fast-2) var(--easing-standard);
}

.ground-appbar__back:hover {
  background: var(--state-layer-hover);
}

/* Title */
.ground-appbar__title {
  flex: 1;
  font-size: var(--font-size-lg);
  font-weight: var(--font-weight-semibold);
  letter-spacing: var(--font-tracking-snug);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: center;
  color: var(--foreground);
}

/* Actions */
.ground-appbar__actions {
  display: flex;
  align-items: center;
  gap: var(--spacing-0-5);
}

.ground-appbar__action {
  width: var(--size-min-width-11);
  height: var(--size-min-width-11);
  border-radius: var(--radius-full);
  background: none;
  border: none;
  color: var(--foreground);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  position: relative;
  transition: background var(--duration-fast-2) var(--easing-standard);
}

.ground-appbar__action:hover {
  background: var(--state-layer-hover);
}

/* ─── Transparent variant ─── */
.ground-appbar--transparent {
  background: transparent;
  color: var(--foreground-inverse, #fff);
}

.ground-appbar--transparent .ground-appbar__title,
.ground-appbar--transparent .ground-appbar__back,
.ground-appbar--transparent .ground-appbar__action {
  color: var(--foreground-inverse, #fff);
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
}

/* ─── Medium flexible variant ─── */
.ground-appbar--medium {
  /* Taller container for medium flexible */
}

.ground-appbar--medium .ground-appbar__inner {
  height: auto;
  flex-direction: column;
  align-items: flex-start;
  padding: var(--spacing-3) var(--spacing-4);
}

.ground-appbar--medium .ground-appbar__row {
  display: flex;
  align-items: center;
  width: 100%;
  height: var(--spacing-11); /* 44px nav row */
  gap: var(--spacing-2);
}

.ground-appbar--medium .ground-appbar__title {
  font-size: var(--font-size-xl);
  font-weight: var(--font-weight-semibold);
  text-align: left;
  padding: var(--spacing-1) 0;
}

.ground-appbar--medium .ground-appbar__subtitle {
  font-size: var(--font-size-sm);
  color: var(--muted-foreground);
  line-height: var(--leading-snug);
}

/* ─── Title hidden (Small / Medium) ─── */
.ground-appbar--no-title .ground-appbar__title,
.ground-appbar--no-title .ground-appbar__subtitle {
  display: none;
}

/* ─── Glass variant ─── */
.ground-appbar--glass {
  background: color-mix(in srgb, var(--background) 70%, transparent);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border: 1px solid var(--border);
  margin: var(--spacing-2) var(--spacing-4) 0;
  border-radius: var(--radius-2xl);
}

/* ─── Large title variant ─── */
.ground-appbar--large .ground-appbar__large-title {
  padding: var(--spacing-2) var(--spacing-5);
  font-size: var(--font-size-3xl);
  font-weight: var(--font-weight-bold);
  letter-spacing: var(--font-tracking-tight);
  color: var(--foreground);
  transition: all var(--duration-normal-2) var(--easing-standard);
}

.ground-appbar--large.ground-appbar--collapsed .ground-appbar__large-title {
  height: 0;
  padding: 0;
  opacity: 0;
  overflow: hidden;
}

/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
  .ground-appbar,
  .ground-appbar__back,
  .ground-appbar__action,
  .ground-appbar--large .ground-appbar__large-title {
    transition: none;
  }
}