Updated: 2026-09-07 09:40 ET
Audited: 2026-07-14 12:12 ET
Items collection, not a fixed
set of named slots — each consumer supplies its own icon asset, label, and click behavior via ActionKey.
Icon as raw text —
♡/♥/↻/✕ Unicode symbols (fine, they inherit CSS color) but the alert toggle used 🔔/🔕, a full-colour emoji
that ignores color entirely and reads as an off-brand icon dropped into a flat design system. Icon is
now ActionColumnIconAsset, masking in the same exported Figma vectors (wwwroot/icons/*.svg) used by
alpa-top-nav-icon-* and the favorite heart elsewhere in the app.
| Token | Value | Meaning |
|---|---|---|
| Base (Neutral) | color: var(--alpa-gray), 20px | Default, inactive state |
| Accent | #c0392b (red) | Saved / alerted / delete — an "active" or "destructive" action |
| Highlight | var(--alpa-blue) | Secondary/info action (e.g. search again) |
| Brand | var(--alpa-navy) | The filled "favorited" heart (Favorites list) — navy like every card heart, never the destructive red (AB#2408 / AB#2679). Same navy the swipe tray's --brand zone uses. |
| Compact | 14px icon (vs. 18px default) | Smaller icon — scaffold's delete-icon sizing. Orthogonal to colour: any variant can be compact. |
| Icon assets | ActionColumnIconAsset: Heart, HeartSelected, Notifications, SearchHistory, Trash | Exported Figma vectors (wwwroot/icons/*.svg), mask-imaged with currentColor — same technique as alpa-top-nav-icon-* (D54). |
Items entry)Two inputs since AB#2679. Vm (ActionColumnViewModel, feed-produced, dispatched through
OnItemClicked by ActionKey) is now optional; the preferred input is Actions — an
IReadOnlyList<SwipeAction> whose records carry icon, title, variant and their own handler. The same list a
SwipeRevealRow renders as a swipe tray renders here as a persistent button row, so the two are two renderings of one
model. Actions wins when both are set; its buttons stop propagation and prevent default because every caller sits the
row inside a navigating card or anchor. Presets (SwipeAction.Remove / ToggleSave / ToggleAlert / Unfavorite) are the
catalogue — see docs/SWIPE-REVEAL-LIST-PLAN.md § 4 for the Favorites onboarding example.
Home: ALPAMobile.Presentation/Components/Library/ActionColumn.razor (migrated 2026-07-15, WI-2254/D61).
| Parameter | Type | Required | Description |
|---|---|---|---|
Vm | ActionColumnViewModel | Yes | Items collection. |
OnItemClicked | EventCallback<ActionColumnItemViewModel> | No | Fires with the clicked item — switch on item.ActionKey to route behavior. |
JumpseatRecentSearchesPage.razor)<SavedSearchCard Vm="@BuildVm(search, i)"
OnActionClicked="@(item => OnActionClicked(item, search, i))" />
@code {
private SavedSearchCardViewModel BuildVm(SavedSearch search, int index)
{
var saved = _savedIndices.Contains(index);
return new SavedSearchCardViewModel
{
Origin = search.Origin, Destination = search.Destination,
TripType = search.TripType, Date = search.Date,
Actions = new ActionColumnViewModel
{
Items = [
new ActionColumnItemViewModel
{
ActionKey = "toggle-save",
Icon = saved ? ActionColumnIconAsset.HeartSelected : ActionColumnIconAsset.Heart,
Title = saved ? "Saved" : "Save search",
Variant = saved ? ActionColumnItemVariant.Accent : ActionColumnItemVariant.Neutral,
},
new ActionColumnItemViewModel
{
ActionKey = "search-again",
Icon = ActionColumnIconAsset.SearchHistory,
Title = "Search again",
Variant = ActionColumnItemVariant.Highlight,
},
],
},
};
}
}
In practice ActionColumn is always composed inside a domain control (Saved Search Card /
Saved Flight Card, D55) rather than used bare — the example above shows the real call site.
Classes live in ALPAMobile/wwwroot/css/alpa-components.css, renamed from .alpa-saved-card-action-btn*
(previously duplicated verbatim as .alpa-saved-flight-card-actions, removed by D55 once the page composed <ActionColumn> directly).
| Class | Scope | Key rules |
|---|---|---|
.alpa-action-column | Row container | display:flex; gap:8px; flex-shrink:0 |
.alpa-action-column-btn | Base button | background:transparent; border:none; color:var(--alpa-gray) |
.alpa-action-column-btn--accent | Variant | color:#c0392b |
.alpa-action-column-btn--highlight | Variant | color:var(--alpa-blue) |
.alpa-action-column-btn--brand | Variant | color:var(--alpa-navy) — renamed from --favorited (AB#2679) so it maps 1:1 onto ActionColumnItemVariant.Brand |
.alpa-action-column-icon | Masked icon span | width/height:20px (14px compact); background-color:currentColor; mask:var(--action-column-icon) center / 18px 18px no-repeat (12px compact) — fixed size, not contain (D54) |
.alpa-action-column-icon--heart / --heart-selected / --notifications / --search-history / --trash | Icon asset | Sets --action-column-icon to the matching wwwroot/icons/*.svg |
ComponentView.razor's dispatcher for consistency, but that path is display-only —
OnItemClicked isn't wired through the dispatcher's generic switch. Compose this atom directly in a
parent component when click behavior is needed.--delete
class; this atom lets any variant be compact independently.Notifications has no
dedicated "off" asset; the off state is colour-only.