Component: Carousel — Horizontal Scrollable Card Collection
ViewModel: CarouselViewModel : ContainerSurfaceViewModel
Work Item: AB#2125
Last Updated: 2026-06-02
Shows how CarouselViewModel properties map to the rendered control.
Title LinkText
│ │
▼ ▼
Section Title View All › ◄── Tap target = Link
┌─────────────────────────────────────────────────┐
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌── │
│ │ │ │ │ │ │ │ │ │
│ │ Item 1 │ │ Item 2 │ │ Item 3 │ │...│ │
│ │ │ │ │ │ │ │ │ │
│ └──────────┘ └──────────┘ └──────────┘ └── │
│ ◄──────────────────── Items ──────────────────►│
│ Horizontal scrollable collection │
│ with right-peek effect (~30% last card) │
└─────────────────────────────────────────────────┘
Items ──────────────► ObservableCollection<ComponentViewModel>
Can contain: Card, ButtonCard, HeroCard,
IconButtonCard, MultiButtonCard
Figma Structure:
controls (FRAME 313×5, fill=#e3e3e3) — scroll track indicator
Ellipse 7 (ELLIPSE 17×17, fill=#007bc2) — scroll thumb / position
label (FRAME 313×21) — section/min label row
Field Label (TEXT, Futura PT Book 16px, color=#05273e)
label (FRAME 313×21) — max/tail label row
Field Label (TEXT, Futura PT Book 16px, color=#05273e)
⚠ Data Gaps: Title, LinkText, Link — sources TBD per use case
Items — collection content TBD per use case
Note: This document serves as a reference spec for the Carousel component.
When implementing specific use cases, derive fromCarouselViewModeland populate
Items,Title,LinkText, andLinkfrom the appropriate data service.
| Property | Status | Source | Notes |
|---|---|---|---|
| Title | ⚠️ TBD | Use-case ViewModel | Section heading text (e.g., "Latest News", "My Documents") |
| LinkText | ⚠️ TBD | Use-case ViewModel | Label for the link action (e.g., "View All") |
| Link | ⚠️ TBD | Use-case ViewModel | Navigation target URL or route for the link tap |
| IsLinkVisible | ✅ Available | ViewModel state | true when Link is non-null/non-empty |
| Items | ⚠️ TBD | Use-case data service | ObservableCollection<ComponentViewModel> — content depends on use case |
| IsLoading | ✅ Available | ViewModel state | Default strategy (no skeleton); set during async data fetch |
| TrackColor | ✅ Available | Figma spec / static | #e3e3e3 — scroll track background (static design token) |
| ThumbColor | ✅ Available | Figma spec / static | #007bc2 — ALPA brand blue (static design token) |
| MinLabelText | ⚠️ TBD | Use-case ViewModel | Left/start label text beneath scroll track |
| MaxLabelText | ⚠️ TBD | Use-case ViewModel | Right/end label text beneath scroll track |
public class CarouselViewModel : ContainerSurfaceViewModel
{
// ── Section header ─────────────────────────────────────────────────────
public string? Title { get; set; } // section heading; e.g. "Latest News", "Media"
// ── Link action ────────────────────────────────────────────────────────
public string? ViewAllText { get; set; } // label for the top-right link (e.g., "View All")
public string? ViewAllLink { get; set; } // navigation route or URL
// ── Scrollable collection ──────────────────────────────────────────────
public ObservableCollection<ComponentViewModel> Items { get; set; } = new();
// Items populated by the use-case ViewModel from the appropriate service:
// e.g., DataManager, IAuthentication, or a domain-specific repository
// ── Scroll track labels ────────────────────────────────────────────────
// MinLabelText: left label beneath the track — TBD per use case
// MaxLabelText: right label beneath the track — TBD per use case
// ── Design tokens (static) ─────────────────────────────────────────────
// TrackColor = Color.FromArgb("#e3e3e3") — Figma: controls fill
// ThumbColor = Color.FromArgb("#007bc2") — Figma: Ellipse 7 fill (ALPA blue)
// LabelFont = "Futura PT Book", 16px
// LabelColor = Color.FromArgb("#05273e")
// ── Loading state ──────────────────────────────────────────────────────
// IsLoading: set true before async fetch, false on completion
// Default strategy: no skeleton overlay — Items collection remains empty
// until data arrives
protected CarouselViewModel() { }
public static async Task<CarouselViewModel> CreateAsync(
string title,
string linkText,
string link,
Func<Task<IEnumerable<CardViewModel>>> itemsFactory,
string minLabelText = "",
string maxLabelText = "")
{
var vm = new CarouselViewModel
{
Title = title,
LinkText = linkText,
Link = link,
IsLinkVisible = !string.IsNullOrEmpty(link),
IsLoading = true
};
try
{
var cards = await itemsFactory();
foreach (var card in cards)
vm.Items.Add(card);
}
finally
{
vm.IsLoading = false;
}
// Label rows (Figma: two `label` FRAMEs beneath the track)
// vm.MinLabelText = minLabelText;
// vm.MaxLabelText = maxLabelText;
return vm;
}
}
"Latest News", "My Documents", "Quick Links"#1a1a1a, font-weight 600"View All")#0066cc, underlinedSharedActionsServiceIsLinkVisible is set to false and the link row is hiddenLink being non-null and non-emptytrue when a link target is providedObservableCollection<ComponentViewModel> populated by the use-case ViewModelCard, ButtonCard, HeroCard, IconButtonCard, MultiButtonCardIsLoading = true; populated on async completiontrue during async data fetch, false on completioncontrols FRAME fill #e3e3e3Ellipse 7 fill #007bc2 (ALPA brand blue)label FRAME)Field Label TEXT node, Futura PT Book 16px, color #05273elabel FRAME)Field Label TEXT node, Futura PT Book 16px, color #05273e| Service | Interface | Notes |
|---|---|---|
| Use-case data service | ⚠️ TBD | Provides Items collection — varies per concrete implementation |
| Navigation | SharedActionsService |
Resolves/opens the Link tap target |
| Authentication | IAuthentication (optional) |
May be needed for scoped data in some use cases |
| Layer Name | Type | Dimensions | Fill | Notes |
|---|---|---|---|---|
slider (root) |
FRAME | 313×63 px | none (transparent) | Outer container |
controls |
FRAME | 313×5 px | #e3e3e3 |
Scroll track background |
Ellipse 7 |
ELLIPSE | 17×17 px | #007bc2 |
Scroll thumb / position indicator |
label (first) |
FRAME | 313×21 px | — | Min/start label row |
Field Label (×2) |
TEXT | variable | #05273e |
Label text nodes inside first label frame |
label (second) |
FRAME | 313×21 px | — | Max/end label row |
Field Label (×2) |
TEXT | variable | #05273e |
Label text nodes inside second label frame |
docs/component-specifications/carousel/carousel-component.htmldocs/component-specifications/card/pilot-card-property-mapping.mdDocument Owner: ALPA Mobile Team
Purpose: Data source analysis and property mapping for Carousel — presentation-layer reference spec