Skip to content

Molecules

Small groups of atoms combined into one interactive unit — fields, pickers, rows, and the travel-booking building blocks.

81 molecules. Every example below feeds modifiers with semantic color tokens (SemanticColor cases, theme.foreground(_:)…) — never a raw Color or CGFloat literal. See the DocC reference for the full API.

Icon+label amenity grid with progressive disclosure.

AmenityGrid([Amenity("Free Wi-Fi", systemImage: "wifi"), ]).columns(2).size(.medium).limit(4).highlighted(["Free Wi-Fi"])

Text field with a suggestion list, synchronous or async.

Autocomplete("Destination", text: $text, suggestions: items)
// async: Autocomplete(text: $text, suggest: { await api.search($0) })

A path trail that collapses long paths behind an ellipsis.

Breadcrumbs([.init("Home", action: { }), .init("Current")], maxItems: 4)

PrimaryButton / SecondaryButton / OutlineButton / GhostButton / LinkButton {#button}

Section titled “PrimaryButton / SecondaryButton / OutlineButton / GhostButton / LinkButton {#button}”

The preset button family — five semantic styles sharing one modifier vocabulary (.size .fullWidth .loading …).

PrimaryButton("Continue") { }

Lays out a row of buttons as one connected group.

ButtonGroup { PrimaryButton("OK") { } }

Month calendar with date selection.

CalendarView(selection: $date)

A single checkbox with a label and validation info messages.

Checkbox("Accept terms", isChecked: $on).accent(.success).infoMessages(error ? [.init("Required", kind: .error)] : [])

A group of checkboxes bound to a selection set.

CheckboxGroup(options: items, selection: $set) { $0 }

ImageChip / CompactChip / ChoseChip / FilterChip / ChipGroup {#chips}

Section titled “ImageChip / CompactChip / ChoseChip / FilterChip / ChipGroup {#chips}”

The chip family — image, compact, price, and filter chips, plus ChipGroup for laying several out together.

CompactChip("Suit", price: "$899", isSelected: $on).rating(4.6) // ChoseChip · ImageChip · FilterChip · ChipGroup

A labeled color-swatch field bound to a Color selection.

ColorField("Brand color", selection: $color).supportsOpacity()

Searchable currency picker with a recents section.

CurrencyPicker(selection: $code, currencies: Currency.common).showsName().searchable().recents(recent)

Date picker field with formatting styles and a locale.

DateField("Check-in", date: $date).style(.custom("EEE, d MMM")).clearable()

A single selectable date + price card, as used inside DatePriceStrip.

DatePriceCard(DatePriceItem("18 Jul", price: 1_767.99), isSelected: true) { pick() }.currency("TRY").cheapest()

A horizontal strip of date + price cards; DatePriceCard is a single selectable card.

DatePriceStrip([DatePriceItem("18 Jul", price: 1_767.99), ], selection: $i).columns(3).highlightCheapest()

Anchored action menu with item roles, dividers, and edge placement.

Dropdown(items: [.init("Rename", systemImage: "pencil"), .divider, .init("Delete", systemImage: "trash", role: .destructive)]) { trigger }.edge(.bottomTrailing)

A field-styled button that opens a picker or sheet.

FieldButton("2 Passengers · Economy") { openSheet() }.label("Passengers").icon("person.2.fill")

Groups fields under a title with helper text.

Fieldset("Contact") { inputs }.helper("")

File picker field with the picked file’s name on display.

FileInput("Passport") { pick() }.fileName(name)

A group of filter options bound to a single selection.

FilterGroup(options: items, selection: $sel) { $0 }

A labeled checkbox filter row with a result count.

FilterRow("Direct", isOn: $direct).count(128).icon("airplane") // Checkbox atom + title + count

Origin → destination route line with stop count.

FlightRoute(from: "IST", to: "AYT", departure: dep, arrival: arr).stops(1).nextDay()

Rooms & guests stepper group for travel booking flows.

GuestSelector(selection: $guests).showsRooms(true).showsInfants(false).maxTotal(9)

Stepper-backed numeric field with a range, step, and unit.

InputNumber("Max price", value: $n, range: 0...10000).step(50).unit("$")

Installment option picker with monthly and total amounts.

InstallmentPicker([InstallmentOption(count: 3, total: 9_900, monthly: 3_300), ], selection: $count).currency("TRY")

InstallmentSelector {#installmentselector}

Section titled “InstallmentSelector {#installmentselector}”

Installment plan picker with interest-free and recommended badges.

InstallmentSelector(total: 12_000, options: [1, 3, 6, 12], selection: $months).interestFreeUpTo(3).recommended(6).surcharge([12: 750])

A layover duration row with a short-connection warning state.

LayoverRow(duration: "2h 15m", airport: "Istanbul (IST)").warning("Short connection")

Price pill annotation for map pins.

MapPriceMarker("₺1.250").selected(isActive).icon("heart.fill") // in any Map annotation

Multi-line text field with a character counter.

MultiLineTextInput("Notes", text: $text).size(.small).characterLimit(200).countStyle(.remaining)

Multi-selection dropdown field.

MultiSelect("Cities", options: items, selection: $set) { $0 }.optionEnabled { $0.inStock }.loading(loading)

One-time-passcode digit entry with a resend timer.

OTPInput(code: $code) { verify($0) }
.digitCount(6).secure().resend(interval: 30) { resend() }

Numbered page navigation with a jump-to-page control.

Pagination(current: $page, total: 50).window(sibling: 2).jumper()

A passenger summary row with seat and check-in status.

PassengerRow("Alex Morgan").type("Adult").subtitle("Passport · TR12345").seat("14C").status("Checked in").onEdit { }

Card number/expiry/CVV field with brand auto-detection.

PaymentCardField(number: $n, expiry: $e, cvv: $c).holder($name) // brand auto-detect + 4-4-4-4 / MM/YY

Itemized price breakdown with discounts and extras.

PriceBreakdown(190_960).note("2 rooms · 4 nights").original(248_000).discountBadge("-23%").extra("Extra 8%", 175_683)

Price-distribution bars layered over a range slider.

PriceHistogram(bins: counts, lowerValue: $low, upperValue: $high, in: 0...5_000).showsBounds().resultCount(n)

Per-day fare bar chart with paging.

PriceTrendChart(points, selection: $day).title("July").onPage(prev: , next: ) // per-day fare bars

Step, carousel, or video progress readout.

ProgressIndicator(variant: .carousel, current: 2, total: 8).stepText(.slash)

A +/- stepper bound to a numeric range.

QuantityStepper(value: $qty, range: 0...10)

A single radio option bound to a selection.

RadioButton(isSelected: $on).accent(.error)

RadioGroup / RadioButtonGroup {#radiogroup}

Section titled “RadioGroup / RadioButtonGroup {#radiogroup}”

A group of radio options bound to a selection; RadioButtonGroup is the tag-based variant.

RadioGroup(options: items, selection: $sel) { $0 }

Dual-handle range slider with marks.

RangeSlider(lowerValue: $lo, upperValue: $hi, in: 0...1000).step(50).marks([0, 500, 1000]).onChangeEnd(search)

A recent-search summary row with a rerun action.

RecentSearchRow(from: "IST", to: "AYT") { rerun() }.roundTrip().dates("18 – 27 Jul").passengers("2 adults · Economy").onRemove { }

Finger-scrub image gallery — drag across to flip pages.

ScrubGallery(images).accent(.primary) // scrub a finger across to flip pages

Search field with suggestions and a recent-searches list.

SearchBar(text: $text).suggestions(cities).recent(recent).onCommit(search)

A labeled field row that opens a picker — the building block of flight/hotel search forms.

SearchField("From") { openPicker() }.value(code: "IST", title: "Istanbul", subtitle: "All airports")
// or fully custom: SearchField("Dates") { }.content { DateRange(…) }.onClear { }

Segmented picker over a set of items.

SegmentedControl([SegmentItem("List", systemImage: "list.bullet")], selection: $i)

Single-selection dropdown field, with optional search and loading state.

Select("City", options: items, selection: $city) { $0 }.searchable().loading(loading)

A lightweight select trigger box.

SelectBox("Country", options: items, selection: $sel) { $0 }

Single-value slider with marks and a value tooltip.

Slider(value: $v, in: 0...8).marks([0: "0", 8: "Max"]).showsValueTooltip()

An inline algorithmic tip/nudge banner.

SmartSuggestion("Berlin outbound is 12% cheaper on Sat 13 Sep.").label("Smart tip").tint(.success).onTap { }

A row of sort-option summaries; SortTab is a single tab within it.

SortSummaryBar([SortOption("Best", value: "₺2.777", subtitle: "1h 07m", icon: "star.fill"), ], selection: $sort).onMore { }

A single sort-option tab, as used inside SortSummaryBar.

SortTab(SortOption("Best", value: "₺2.777", subtitle: "1h 07m", icon: "star.fill"), isSelected: true) { select() }

A labeled statistic with a trend indicator and an icon.

Stat(title: "Bookings", value: "1,284").icon("ticket").trend(.up("+12%"))

A labeled +/- counter row (passengers, rooms, quantity).

StepperRow("Adult", value: $adults).subtitle("+12 yrs").range(1...9) // passenger/room/quantity counter

Numbered step tracker with a state per step.

Steps([.init("Cart", description: "2 items", state: .done), .init("Pay", state: .error)]) { active = $0 }

A single search-suggestion row, with nested sub-airport support.

SuggestionRow("Ankara, Turkey") { pick() }.icon("airplane").code("ANK").subtitle("Any").highlight(query) // .nested() for sub-airports

The primary text field — icons, addons, formatting, and declarative validation.

TextInput("Email", text: $t).keyboard(.emailAddress, contentType: .emailAddress, submit: .next)

A single configurable button — color, variant, size, and shape all as modifiers.

ThemeButton("Save") { }.color(.success).variant(.soft).size(.medium).shape(.pill)

A picker for switching between named themes.

ThemeController(options: [.init(name: "oceanTheme", label: "Ocean")], selectedName: $name)

Light/dark theme switch.

ThemeToggle(isOn: $on).accent(.success).symbols(on: "checkmark")

A group of toggle switches bound to a selection set.

ToggleGroup(options: items, selection: $set, label: { $0 })

Anchored hint bubble with a placement edge and a color.

anchorView.tooltip("Hint", isPresented: $shown, edge: .top, color: .primary)

Hierarchical tree selection field with cascading selection.

TreeSelect("Cities", nodes: tree, selection: $set, initiallyExpanded: ["tr"]).cascade().searchable()

One-way / round-trip / multi-city segmented toggle.

TripTypeToggle(["One way", "Round trip", "Multi-city"], selection: $trip).icons([])

Even spacing between inline or stacked children — direction, size, align, wrap (Ant Space).

Space { Button("Save") { }; Button("Cancel") { } }.size(.large).wrap()

A flexbox container with main-axis justify and cross-axis align distribution (Ant Flex).

Flex { Tag("A"); Tag("B"); Tag("C") }.justify(.spaceBetween).align(.center)

A scroll-spy link rail; the active section highlights as you scroll (Ant Anchor).

AnchorNav(sections, active: $current).onSelect { proxy.scrollTo($0, anchor: .top) }

Two panes separated by a draggable, clamped divider (Ant Splitter).

Splitter(.horizontal) { Sidebar() } second: { Detail() }.bounds(min: 0.2, max: 0.8)

Pick a value from a multi-level option tree, one column per level (Ant Cascader).

Cascader(regions, selection: $path).placeholder("Region")

Move items between a source and a target list with checkboxes + arrows (Ant Transfer).

Transfer(items, target: $enabled).titles("Available", "Enabled")

A textarea where typing @ opens a filterable mention list (Ant Mentions).

Mentions(text: $note, options: teammates).placeholder("Write a note…")

A Pinterest-style grid; items flow into the shortest column (Ant Masonry).

Masonry { ForEach(photos) { Card($0) } }.columns(2).spacing(.sm)

A hierarchical tree with expand/collapse and optional cascade checkboxes (Ant Tree).

TreeView(nodes, selection: $checked).checkable()

An equal-column grid with a token gutter; fixed or responsive-adaptive (Ant Grid).

ColumnsGrid { ForEach(items) { Card($0) } }.columns(3).gutter(.md)