Skip to content
Barua UI v0.2
Foundations

Layout

SwiftUI-inspired layout primitives for the web. Stack, HStack, VStack and Spacer compose exactly like their Swift namesakes; containers, grids, split views and scroll areas cover the rest. Everything spaces itself from the 4px token scale — no margin fiddling.

Container

.b-container centers content and clamps its width — the default cap is --b-container-lg (64rem). Size variants swap the cap; --fluid removes it. Wider variants clamp to this page's width here, which is exactly what they'd do on a narrow viewport.

--sm · 40rem
--md · 48rem
default · 64rem
--xl · 80rem
--fluid · no cap

Stack (VStack)

.b-stack (alias .b-vstack) is a vertical flex column with a token gap — the default building block for any view. Tune spacing with the gap scale — .b-gap-0, .b-gap-1, .b-gap-2, .b-gap-3, .b-gap-4, .b-gap-6, .b-gap-8 — instead of margins on children.

1
2
3

Alignment

Cross-axis alignment mirrors SwiftUI's VStack(alignment:)--start, --center and --end (children stretch by default).

--start
--start
--center
--center
--end
--end

HStack

.b-hstack lays children out in a row, vertically centered. The alignment modifiers are shared with Stack — add .b-stack--between to spread children across the row.

1
2
3
1
2
3

Title + Spacer + action

The classic SwiftUI bar: a title, a .b-spacer to eat the middle, and a trailing action.

Inbox 12
Space siblings with the stack's gap (.b-gap-*) and push them apart with .b-spacer or --between — one knob, consistent rhythm.
Don't sprinkle ad-hoc margins on children to fake spacing; mixed margins fight the gap and break at the first refactor.

Grid

.b-grid is a 12-column grid by default: set --b-cols (or a .b-grid--2/3/4/6 preset) and place children with .b-col-span-* classes.

The presets are responsive, and the base 12 is not. A row of N equal cards is a desktop shape: three pricing cards on a 390px phone came out 110px wide with one word per line, so .b-grid--2/3/4/6 start at one column and earn more at 36rem and 62rem. The 12-column base is an explicit layout you placed by hand, so it is left alone; anything that genuinely wants a fixed count at every width sets --b-cols itself, which is what the presets are written in terms of.

span 4
span 4
span 4
span 6
span 6
span full

Auto-fit

.b-grid--auto packs as many tracks of at least --b-col-min (default 16rem) as fit — responsive with zero media queries.

1
2
3
4
5
6

Flex

A thin display: flex shorthand for when a stack is too opinionated. --center and --between handle both axes; .b-grow and .b-shrink-0 tune individual children.

--between
--between
--between
fixed
b-grow
fixed

Split View

Master–detail in one line of markup: .b-split stretches .b-panel children to equal height with a .b-resize-handle between them. Make the sidebar .b-resizable and dragging is native CSS resize — no JavaScript.

Sidebar
Detail
Accessibility. The native resize grip is pointer-only. Give the handle role="separator" with aria-orientation and an aria-label, and offer a keyboard path — arrow-key handling on the handle or a width control elsewhere in the view.

Resizable Panel

.b-resizable adds the browser's native resize grip to any panel — horizontal by default, --vertical for height. Look for the grip in the bottom-trailing corner; min and max bounds are built in.

Drag my corner →
Drag me taller ↓

Panel

.b-panel is the plain workhorse surface: surface background, hairline border, large radius. --plain strips the chrome for panels that only exist to scroll or resize.

b-panel
b-panel--plain

Section

.b-section adds generous block padding between page regions — the vertical rhythm of a landing or settings page. --tight is the compact cut. Dividers shown here only to make the padding visible.


b-section--tight

b-section

Card Grid

A responsive shelf of cards: auto-fill columns at least 17rem wide, token gap, no breakpoints. The default answer for dashboards and galleries.

Reports
Weekly digest
Automations
4 running
Contacts
1,208 people
Billing
Paid until March

Masonry

CSS-columns masonry for content of uneven height — pins, notes, image cards. Items flow down each column in source order; cap the column count with --b-masonry-cols.

1
2
3
4
5
6

Scroll Area

Give it a height and .b-scroll-area contains the scrolling: overscroll never leaks to the page and the scrollbar gutter stays stable. --fade masks both edges so clipped content looks intentional.

Row 1
Row 2
Row 3
Row 4
Row 5
Row 6
Row 1
Row 2
Row 3
Row 4
Row 5
Row 6
Accessibility. A scrollable <div> isn't keyboard-reachable on every browser. Add tabindex="0" plus role="region" and an aria-label (as above) so keyboard users can focus and scroll it.

Spacer

Straight from SwiftUI: .b-spacer is an empty flex-1 element that absorbs leftover space. Push row siblings apart, or pin a footer to the bottom of a fixed-height stack.

Leading
Trailing
Content
Pinned footer

Divider

Hairline separators drawn with --b-separator. Horizontal by default; use them sparingly — a stack gap is often separation enough.

Above the fold


Below the fold

Vertical

--vertical separates inline actions inside an hstack or toolbar.

Inset

--inset starts the hairline past the leading edge so it aligns with list text — the iOS settings look.

AK
Asha Kimaro
asha@barua.app
JM
Juma Mwita
juma@barua.app
NK
Neema Kessy
neema@barua.app

Label

--label centers a caption between two hairlines — the classic "or" between sign-in choices.

Accessibility. An <hr> maps to role="separator" and is announced. That's right for meaningful breaks like the labelled "or"; mark purely decorative hairlines aria-hidden="true" so screen readers skip them.

Responsive

Barua is mobile-first and the components own their own shrinking — pages should not need bespoke media queries. .b-dashboard spans collapse to full width below md (768px) and the column grid engages above it. Floating surfaces clamp themselves to the viewport: toasts, notifications, menus and the command palette cap their width, and the dock tray scrolls when crowded. The breakpoint scale lives in Foundations; when a component should respond to its box rather than the viewport, use container queries below.

Wrapping toolbars

Add .b-stack--wrap to any .b-hstack so a crowded row reflows onto new lines instead of squeezing its items — the pattern behind the ambient example’s header.

Inbox Sent Archive

Visibility utilities

.b-hide-mobile and .b-hide-desktop flip at md — use them to drop rails, inspectors and secondary chrome on phones. Resize the window to see them trade places.

Desktop only · .b-hide-mobile Mobile only · .b-hide-desktop

Stage

.b-stage turns a page into a fixed screen: full viewport height, no scrolling — the layout for ambient walls, kiosks and TV-style surfaces where everything must be visible at once. Its .b-container child stretches, a .b-dashboard inside shares the remaining height between rows, and cards clip internally instead of growing the page. Below md it steps aside and the page scrolls like any phone screen. The ambient example is built on it.

This is the Barua stance, not a special case: on desktop there is no page scroll. A surface ends at the screen — chrome stays put, and only designated panes move: .b-scroll-area, a workspace main, a list. Every example ships this way; build products the same way.

Fits
Rows share the stage height.
Clips
Overflowing content clips inside the card — the page never scrolls.

Container Queries

SwiftUI's ViewThatFits, the CSS way: mark a wrapper .b-cq and children respond to the container's width — .b-cq-show-sm/md/lg appear at ≥24/40/56rem, .b-cq-hide-* retire. The same component adapts in a sidebar and in a full-width main without media queries.

Narrow container → compact Wide container content
Narrow container → compact Wide container content — this card is past the 24rem detent, so the fuller layout renders.

Text that fits

SwiftUI has minimumScaleFactor; CSS has no direct equivalent, but a container query unit does the same job honestly. .b-fit-text sizes its child as a fraction of the container's width, clamped so it can never become unreadable at one end or absurd at the other.

TZS 4,208,500
TZS 4,208,500
TZS 4,208,500

Same figure, three widths, one class. Tune it with --b-fit-min, --b-fit-max and --b-fit-scale. It is for a single line that must not wrap — a total, a headline figure, a name in a narrow column — not for paragraphs, which should wrap rather than shrink.