Picker
Fixed 106×72 option tiles — value, caption and an optional status strip; a selected tile inverts and shows a check.
pickerOpen in Figma ↗A compact selectable tile displaying a value, a description label, and an optional status badge — used for choosing between discrete options in a constrained layout.
Use for: Horizontal picker rows where the user selects one value from a set of discrete options — such as a data amount, a duration, or a quantity — where each option needs a value and a unit or description label.
Not for: General navigation or filtering — use chips or filter-pill instead. Not for free-form input — use a text field instead.
Choosing: Use color-scheme=default on light and sunken surfaces. Use color-scheme=inverse on glass, midnight, or dark surfaces — the tile renders with a white glass fill and inverse text tokens. Toggle badges to show or hide the status badge at the bottom of the tile. Set state=selected to highlight the active option. Set state=disabled to prevent interaction and reduce visual prominence.
Rules: Width is fixed at 106px, height at 72px — do not resize. Padding is 20px top, 8px left and right. The status badge is 16px tall and spans the full tile width — do not change its dimensions. Edit the value and description label via text properties on the instance. Do not place pickers outside a horizontal picker row — they are always grouped with sibling pickers representing alternative options.
import SwiftUI import EandTokens // V1.2 picker tile: fixed 106×72, r16, centred. Value title/sm over a body/xs caption // (20pt top, 8pt sides). Selected swaps the fill to midnight-raised with inverse ink // and adds a 20pt check-circle at 6,6 from the top-end. Optional neutral sm badge strip. struct PickerOption: View { let value: String; let caption: String; let selected: Bool var body: some View { VStack(spacing: 0) { Text(value).font(.system(size: EandTypography.titleSm.size, weight: EandTypography.titleSm.weight)) Text(caption).font(.system(size: EandTypography.bodyXs.size)) .foregroundColor(selected ? EandColor.textDefaultInverse : EandColor.textDefaultSubtle) Spacer(minLength: 0) } .foregroundColor(selected ? EandColor.textDefaultInverse : EandColor.textDefaultDefault) .padding(.top, EandSpacing.xl).padding(.horizontal, EandSpacing.sm) .frame(width: 106, height: EandScale.scale72) .background(selected ? EandColor.surfaceRaisedMidnight : EandColor.surfaceSunkenDefault) .overlay(alignment: .topTrailing) { if selected { Image(systemName: "checkmark.circle.fill").font(.system(size: EandIcon.lg)) .foregroundColor(EandColor.surfaceBaseInverse) .frame(width: EandIcon.xl, height: EandIcon.xl).padding(6) } } .clipShape(RoundedRectangle(cornerRadius: EandRadius.radius6)) } }
When to use
- Use to choose one value from a small set shown side by side, such as top-up amounts.
Pickermanages the selection;PickerOptionis the standalone tile for custom layouts. - Don't use for a long list — use an Input of
type="dropdown". For options that combine, use Checkbox; to switch views, Tabs.
Anatomy
- Value —
title/sm, centred. Caption —body/xsbeneath it, such as a unit. - Badge — a string or number renders the neutral
smstatus Badge as a strip along the bottom of the tile. Any other node renders as given. Hidden while disabled. - Selected — the fill and ink swap, and a check circle appears at the top end. On
defaultandlightthe tile turns midnight with white text; oninverseandglassit turns white. - Disabled — disabled ink, no badge. A disabled tile never shows as selected.
The surface names predate V1.2 and map to Figma's surfaces as follows:
surface | Figma surface | Tile fill |
|---|---|---|
default | sunken | surface/sunken/default |
light | default | surface/canvas/default |
inverse | midnight | surface/raised/midnight |
glass | glass | surface/glass/white/lg |
Props
| Prop | Type | Default | Description |
|---|---|---|---|
options | PickerOptionData[] | — | |
defaultValue? | number | — | |
onChange? | ((index: number) => void) | — | |
surface? | 'default' | 'inverse' | 'light' | 'glass' | default | |
value? | number | — | Selected index (controlled). |
| Prop | Type | Default | Description |
|---|---|---|---|
badge? | ReactNode | — | Status badge along the bottom of the tile (Figma badges). A string or number renders the
published neutral sm status badge across the tile; any other node renders as given.
Hidden while disabled. |
caption? | ReactNode | — | Secondary line under the value (body/xs) — e.g. a unit. |
disabled? | boolean | — | |
onClick? | (() => void) | — | |
selected? | boolean | — | |
surface? | 'default' | 'inverse' | 'light' | 'glass' | default | |
value? | ReactNode | — | Primary text (title/sm, centred). |
Design
Figma source: picker — etisalat Consumer App DSL V1.2
- A fixed 106×72 tile (
scale/72),border-radius/6(16), content centred with 20px top and 8px side padding. - Selected, default scheme:
surface/raised/midnightwithtext/default/inverse. Inverse scheme:surface/raised/defaultwithtext/default/defaultandsubtle. - The check is
check-circle-filled, 20px in a 24px box, 6px from the top and end edges. - Badge strip: a 2px inset and corner radii 6/6/28/28, so the strip follows the tile's curve. The bottom 28 has no token.
- Glass:
surface/glass/white/lgbehind a 20px backdrop blur.