Split bar
A segmented progress bar that visualises how an expense is divided across people. Each person gets a color-coded segment — ink, coral, teal, butter — that springs in sequentially. At a glance you see who owes what, before you read a single number.
Variants
Four-way split — Goa Airbnb ₹12,000
Even split — Farzi Cafe ₹4,200
Settled — all clear
Segments are mapped to person slots in order: ink (you, always first), coral, teal, butter, then back to muted fills for groups larger than four. Each segment width is the person's share as a percentage of the total.
Spring animation staggers 80ms between segments so they read left-to-right — not as a simultaneous burst.
Sizes
Prominent — 12px
Subtle — 6px
| Size | Class | Height | Use case |
|---|---|---|---|
| Prominent | .split-bar-prominent | 12px | Expense summary card, settle card header |
| Subtle | .split-bar-subtle | 6px | Compact list items, inline breakdown |
States
Default — split active
Loading / skeleton
Settled — fully resolved
| State | Visual | When |
|---|---|---|
| Default | Color segments, spring animation on mount | Expense has outstanding balances |
| Loading | Single mute fill at 50% opacity, no animation | Data is fetching |
| Settled | Full-width teal, no animation | All balances are zero — celebrated state |
On dark surfaces
Prominent on dark — Swiggy order ₹840
Subtle on dark
Segment colors are unchanged on dark surfaces — they carry enough contrast. The muted fill for the loading state uses --dark-border instead of --ink-line.
Anatomy
Wrapper (overflow:hidden, border-radius pill)
Segment (flex-shrink:0, width = share%)
Color slot (sb-ink / sb-coral / sb-teal / sb-butter)
| Part | Element | Notes |
|---|---|---|
| Wrapper | .split-bar | Flex container, pill radius, overflow hidden. Width is always 100% of its parent. |
| Segment | .split-bar-segment | Width set inline as a percentage matching the person's share. Never use fractions — round to 1 decimal. |
| Color slot | .sb-ink .sb-coral .sb-teal .sb-butter | Slot order is fixed — ink is always "you", coral is person 2, and so on. |
| Label row | .split-bar-labels | Optional. Mirrors the segment widths exactly. Each label is truncated with ellipsis if it overflows. |
Usage
Do
Always put "you" in the first ink slot. Keep label widths in sync with segment widths. Use prominent size in expense summary cards and subtle size for inline breakdowns.
Don't
Don't add more than 5 segments — past 4 the bar becomes illegible. Don't skip the animation on first mount — it's how users read the proportions. Don't use the split bar for progress (use cap meter instead).
Do
Show the settled state (full teal) when all balances are zero. It's a moment worth celebrating — don't leave the bar empty or hidden.
Don't
Don't use custom colors outside the four defined slots. The palette is intentional — it maps to avatar colors for consistency across the app.
Accessibility
Screen readers
The split bar is decorative — the information it conveys must also be present in text (e.g. "Aarav ₹3,840 · Priya ₹3,360"). Wrap the bar in
aria-hidden="true" and ensure the parent context has a readable breakdown elsewhere on the same screen.
Motion
The spring entrance animation runs once on mount. Users with
prefers-reduced-motion: reduce should receive static segments — add a media query that sets animation: none on .split-bar-segment.
Contrast
All four segment colors (ink, coral, teal, butter) pass WCAG AA against the warm paper and warm canvas backgrounds at 12px and above. The muted fill at 50% opacity is decorative-only; it is never the sole indicator of status.
Code
HTML
<!-- Prominent split bar, 4-person Goa Airbnb --> <div class="split-bar-wrap" aria-hidden="true"> <div class="split-bar split-bar-prominent"> <div class="split-bar-segment sb-ink" style="width:32%"></div> <div class="split-bar-segment sb-coral" style="width:28%"></div> <div class="split-bar-segment sb-teal" style="width:24%"></div> <div class="split-bar-segment sb-butter" style="width:16%"></div> </div> <div class="split-bar-labels"> <div class="split-bar-label" style="width:32%">Aarav ₹3,840</div> <div class="split-bar-label" style="width:28%">Priya ₹3,360</div> <div class="split-bar-label" style="width:24%">Rohan ₹2,880</div> <div class="split-bar-label" style="width:16%">Kabir ₹1,920</div> </div> </div> <!-- Settled state --> <div class="split-bar split-bar-prominent" aria-hidden="true"> <div class="split-bar-segment sb-teal" style="width:100%"></div> </div> <!-- Reduced motion override --> <style> @media (prefers-reduced-motion: reduce) { .split-bar-segment { animation: none; } } </style>
CSS classes
| Class | Purpose |
|---|---|
.split-bar | Base wrapper — flex, pill radius, overflow hidden |
.split-bar-prominent | 12px height — expense summary, settle card |
.split-bar-subtle | 6px height — compact list items |
.split-bar-segment | Single person's colored portion, with spring animation |
.sb-ink | Slot 1 — always "you" |
.sb-coral | Slot 2 — person 2 |
.sb-teal | Slot 3 — person 3, also used for settled state |
.sb-butter | Slot 4 — person 4 |
.sb-mute | Loading placeholder fill |
.split-bar-labels | Optional label row below the bar |
.split-bar-label | Individual label — width must match corresponding segment width |
Design tokens used
| Token | Value | Role |
|---|---|---|
--ink | #171513 | Slot 1 fill (you) |
--coral | #E76F51 | Slot 2 fill |
--teal | #0E7C66 | Slot 3 fill, settled state |
--butter | #F4C94E | Slot 4 fill |
--ink-line | #DDD2B8 | Muted loading fill |
--r-pill | 999px | Wrapper border radius |
--ease-spring | cubic-bezier(0.34,1.56,0.64,1) | Segment entrance animation |
--d-slow | 420ms | Animation duration |