← Back to Index

Button Pill Figma: button pill primitive tier

Updated: 2026-07-06 17:22 ET

Audited: 2026-06-26

Segmented tab-group control — pill-shaped active/inactive toggle inside a white pill container
Figma node: 5048:13572 (inactive) / 5048:13573 (active) · Tab group: 5048:13576 · Screen: Notifications 5060:14989 · file key: psH738AqHDxuMyFm897f9r
Live-file master (gap-audited 2026-07-06, D46): node 4245:5754 · COMPONENT_SET 167×158 (Property 1=default 127×31, Property 1=selected 109×31) · live file owEYzHf7FrHRvWC2u82UOl ("ALPA mobile app"). Confirmed the same component as above — the "pill button" spelling seen in some older docs was a word-order transcription slip, not a Figma rename.
Primitive tier — domain-free. A single button pill is one selectable item inside a tab group container. The Notifications screen uses a two-tab configuration: "Comms" and "Flight Finder". Switching tabs filters the notification list — this is not two separate screens, it is one screen with two filtered feeds. Figma annotation: "Notifications — two-tab segmentation. Flight Finder tab vs. Comms tab. Switching changes the list source; the same card serves both (comms variant on the Comms side)." The tab group outer container is a white rounded pill (border-radius:32px); individual pills have border-radius:24px.
Design tokens sourced from Figma file key psH738AqHDxuMyFm897f9r · Component: button pill (5048:13572–73) in tab group (5048:13576) · Screen: Notifications (5060:14989) · captured 2026-06-26

Live CSS Preview

Left tab active (Flight Finder selected)
Right tab active (Comms selected)
As seen in Figma (Comms inactive / Flight Finder active)
3-option group — Flight Finder results (Multileg active)

Design Tokens

Dimensions — Tab Group

Width
345 px (full-width in 393px screen − 2×24px margins)
Outer border-radius
32 px (rounded-[32px])
Tab group background
interactive/fields = white

Dimensions — Individual Pill

Width
flex: 1 (equal split within tab group)
Pill border-radius
24 px (rounded-[24px])
Padding vertical
8 px (--tiny)
Padding horizontal
16 px (--xsmall)

Colors — Inactive

Background
surface/default = white
Label text
text/primary #05273e

Colors — Active

Background
interactive/blue-lt #007bc2
Label text
text/on-brand = white

Typography

Font family
Font Family/Body (Futura PT Demi)
Font weight
Demi (500)
Font size
15 px (--font-size/other/button)
Line height
1 (none)
Letter spacing
0.6 px (tracking-[0.6px])
Text transform
uppercase
White-space
nowrap

Variants

StateFigma nodeBackgroundText color
Inactive (default)5048:13572surface/default = whitetext/primary #05273e
Active (selected)5048:13573interactive/blue-lt #007bc2text/on-brand = white

Layer Tree

└── tab group · 345px · bg:interactive/fields · border-radius:32px
    └── slot · flex row · justify-between · width:100%
        ├── button pill [Comms — inactive] · flex-1 · bg:surface/default · radius:24px
        │    └── [Label] · TEXT · Futura PT Demi 15px · uppercase · text/primary
        └── button pill [Flight Finder — active] · flex-1 · bg:interactive/blue-lt · radius:24px
            └── [Label] · TEXT · Futura PT Demi 15px · uppercase · text/on-brand (white)

ViewModel

Tier: primitive. No dedicated ViewModel needed — the tab group is driven by an index or enum from the page ViewModel.

└── ButtonPillViewModel : ComponentViewModel (spec-only — not in ComponentViewModels.cs)
    ├── Label : string — tab label text (e.g. "Comms", "Flight Finder")
    └── IsActive : bool — true = blue fill + white text

Note: ButtonPillViewModel is spec-only and will not be added to ComponentViewModels.cs until implementation. The tab group state is managed by the consuming page ViewModel (e.g. NotificationsViewModel.ActiveTab).

Usage Context

ScreenNodeTabsBehavior
Notifications5048:13576Comms / Flight FinderSwitches filtered notification feed — same card component, different data source. Designer annotation: one screen, two filtered feeds — not two screens.
Flight Finder results (4713:25117)4713:25124Nonstop / One Stop / Multileg3-option filter on flight search results. Confirmed labels from Figma. Gap between pills: 33px in this instance.

Distinct from interior-tab-nav (underline + font switch, no fill, scrollable) — that is a different component for named sub-screen navigation. The segmented pill control is a compact in-place filter, always fully visible.

Developer Notes

Blazor Component API

Target home: ALPAMobile.HybridUi. Two components: ButtonPill.razor (individual pill) and TabGroup.razor (outer container managing the tab collection).

ParameterComponentTypeRequiredDescription
LabelButtonPillstringYesTab label. CSS applies uppercase.
IsActiveButtonPillboolYesWhen true, applies alpa-btn-pill--active modifier (blue fill, white text).
OnClickButtonPillEventCallbackYesFires on tap. Consumer updates active tab state in page ViewModel.
TabsTabGroupIReadOnlyList<ButtonPillViewModel>YesOrdered list of tab definitions. Renders as one ButtonPill per entry.
OnTabSelectedTabGroupEventCallback<int>YesIndex of selected tab. Consumer updates page state and re-filters content.

Razor Usage (target)

@* Notifications page — two-tab group *@
<AlpaTabGroup Tabs="@Vm.Tabs"
              OnTabSelected="@Vm.SelectTab" />

@* Or using individual pills within a custom layout *@
<div class="alpa-tab-group">
  <AlpaButtonPill Label="Comms"
                  IsActive="@(Vm.ActiveTab == 0)"
                  OnClick="@(() => Vm.SelectTab(0))" />
  <AlpaButtonPill Label="Flight Finder"
                  IsActive="@(Vm.ActiveTab == 1)"
                  OnClick="@(() => Vm.SelectTab(1))" />
</div>

CSS Class Reference (target)

Classes will live in ALPAMobile.HybridUi/wwwroot/css/alpa-components.css under the alpa-tab-group and alpa-btn-pill BEM blocks.

ClassScopeKey rules
.alpa-tab-groupOuter containerbackground:var(--interactive-fields, white); border-radius:32px; display:flex; width:345px
.alpa-tab-group__slotInner layout rowdisplay:flex; align-items:center; justify-content:space-between; width:100%
.alpa-btn-pillIndividual pillflex:1; display:flex; align-items:center; justify-content:center; padding:8px 16px; border-radius:24px; border:none; cursor:pointer; background:var(--surface-default, white); font-family:var(--font-family/body); font-weight:500; font-size:15px; color:var(--text-primary); text-transform:uppercase; letter-spacing:0.6px; line-height:1; white-space:nowrap
.alpa-btn-pill--activeActive pill modifierbackground:var(--interactive-blue-lt); color:var(--text-on-brand, white)