Skip to content
Barua UI v0.2
Patterns

Mobile

iOS-feeling patterns for the small screen — glass chrome, safe areas, 44pt targets. Headers collapse from large titles, tab bars blur the content behind them, and rows swipe to reveal actions.

Mobile Header

.b-mobile-header is the sticky glass chrome at the top of a mobile view: a three-column __bar with a .b-back-btn at the start, a centered __title and an __action--end slot. One note on the demos on this page: mobile chrome is normally position: fixed or sticky, so each demo sits inside a phone-width frame and the component gets an inline position: static override to render inside it — drop the override in a real app.

Message

Large title

Add __large-title under the bar for the iOS large-title pattern; on scroll, collapse it and reveal the small centered title.

Inbox

Mobile Navigation

Mobile navigation is a pattern, not one component. Follow the iOS conventions: the back button sits at the start of the header, is labelled with the previous screen's title (never just "Back"), and the current screen's title stays centered. Push deeper views onto a stack; switch top-level sections with the Bottom Tab Bar below. For overflow destinations, use the navigation drawer from the Navigation page, or the Mobile Menu as a full-screen list.

Mirror iOS conventions — back button labelled with the parent screen, one centered title, tab bar for top-level sections. Muscle memory from the platform transfers straight into your app.
Hide primary actions only behind gestures. Swipes, long-presses and pull-to-refresh are accelerators — every action they trigger must also exist as a visible button or menu item somewhere on screen.

Bottom Tab Bar

.b-bottomnav fixes a glass tab bar to the bottom edge with safe-area padding built in. Use three to five __items, mark the current one with .is-active, and attach a .b-badge--count to an icon for unread counts.

Bottom Sheet

The full .b-bottom-sheet — a <dialog> that springs up from the bottom edge with a scrim — is documented on the Overlays page. Shown here statically inside the frame: a __grabber pill on top of a __body list of actions.

  • Reply
  • Forward
  • Archive
  • Delete

Mobile Menu

.b-mobile-menu is a full-width list of big, thumb-sized rows — each at least the 44px touch target tall. Use it inside a drawer or a full-screen sheet; mark the current destination with .is-active.

Mobile Toolbar

.b-mobile-toolbar is the bottom action bar for the current screen — glass, hairline on top, safe-area padding below, and icon buttons bumped up to the large control size for easy reach.

Swipe Actions

.b-swipe is a CSS-only take on the iOS swipe-to-act row: a horizontal scroller with scroll-snap-type: x mandatory. The __content row fills 100% of the width and snaps to the start; the __actions sit just off-screen and snap to the end. Dragging left reveals them, and the scroll snap makes the row rest either fully closed or fully open — try it, the demo below actually scrolls.

AK
Amina Kassim
Q3 launch review — moved to Thursday, can you make it?
Accessibility. A swipe is invisible to keyboard, switch and screen-reader users — and to anyone who simply doesn't know it's there. Every swipe action needs a visible alternative: the same Flag and Delete must also appear in the row's action menu or the mobile toolbar. The hidden buttons are still real <button>s, so they stay focusable and announced.

Pull to Refresh

.b-ptr is the visual affordance above a list. It sits at height: 0 until your scroll handler adds a state class: .is-pulling springs it open to its full height as the user drags, .is-ready rotates the __arrow 180° to signal "release to refresh", and .is-refreshing swaps the arrow for a spinner while data loads. Shown here frozen in the refreshing state.

Refreshing…
  • JM
    Joseph Mwangi
    Invoice #2214 approved
  • ZH
    Zawadi Hassan
    Design tokens are ready for review

Touch Target

Small controls stay small visually but should never be small to a thumb. The .b-touch-target utility overlays an invisible ::after hit area of at least var(--b-touch-target) — 44px — centered on the control, so a compact close button still catches an imprecise tap. The button below renders at its extra-small size; the whole 44×44 area around it is pressable.

← 44×44 hit area around a tiny button
Accessibility. WCAG 2.5.8 (Target Size — Minimum) makes undersized targets a conformance failure; Barua's --b-touch-target token standardizes on Apple's 44px minimum, comfortably above the WCAG floor. Apply .b-touch-target to any control smaller than 44px, and keep at least a hairline of spacing between adjacent expanded targets so taps don't overlap.

Safe Area

On notched and home-indicator phones, the OS reserves the screen edges and reports them as env(safe-area-inset-*) values. Barua's fixed chrome — .b-mobile-header, .b-bottomnav, .b-mobile-toolbar, .b-bottom-sheet — already pads with them. For your own bars, use .b-safe-area (all four edges) or .b-safe-bottom, which pads with max(var(--b-space-3), env(safe-area-inset-bottom)) so it still breathes on squared-off screens.

The insets report 0 until you opt in with viewport-fit=cover in the viewport meta tag — without it, the browser letterboxes your page instead:

index.html
<meta name="viewport"
      content="width=device-width, initial-scale=1, viewport-fit=cover">

Collapsing Large Title

NavigationStack's signature move: the large title shrinks away as content scrolls, and the bar title fades in. Add data-b-collapse to a .b-mobile-header — barua.js watches the nearest scroll parent and toggles .is-collapsed.

Inbox

Inbox

Scroll this panel — the large title collapses into the bar.

The end.