The service tile — the entry point into a service or vertical: a fixed-size rounded card with a caption title and a catalogue illustration seated by an ImageContainer recipe. A locked customCard configuration promoted into its own component.
v3.0.0
ServiceCard
--
--
--
3.0.0
Overview
-
1
L
-
2
M
-
3
S
1
2
3
States
The state list is complete: the tile rests or it is still loading. Press is runtime feedback inherited from the card family, not a state of the set — see Animation.
Standard
1
2
3
-
1
Surface var(--surface-on-white) — the tile fill.
-
2
Title, Subtitle var(--text-and-icon-primary) — the caption text pinned to the top, above the underlay; long names clamp with an ellipsis. The default — an instance may set another semantic token.
-
3
Artwork The ImageContainer underlay, seated by its recipe — the picture brings its own colors, nothing is tinted, the bleed is clipped at the root radius.
Skeleton
1
2
-
1
Surface Holds var(--surface-on-white) — the fill stays.
-
2
Title Line var(--surface-overlay) — paints the .skeleton-text--caption line that replaces the title. The default — an instance may set another semantic token.
Anatomy
Four parts: the fixed-size root, the title row pinned to the top, the full-bleed artwork underlay beneath it, and the DecorateContainer slot at the top-right — shown as a zone, its promo label is not shipped yet.
1
2
3
4
-
1
The component root .service-card — a fixed-size tile per the Size axis, radius var(--sp-s20).var(--surface-on-white) — the fill; the root clips everything at its radius. Required.
-
2
StartText .service-card__title-row — pinned to the top, above the underlay; a column of caption lines at gap var(--sp-s0)..service-card__line > .service-card__title — the first caption line. Required..service-card__line > .service-card__subtitle — the second line, hidden by default; with the title it forms the accessible name.
-
3
BottomSlot — ImageContainer .service-card__bottom — absolute, stretch-anchored to all four edges (inset 0): the full-bleed underlay. Required..image-container--{l|m|s} — the primitive inside, sized by the slot; the recipe seats the artwork and the bleed is cut at the root edge — the dashed artwork box shows exactly where.
- 4
Layout
L
1
2
3
1
Title
Title
Subtitle
Title
Standard
Title
Expanded
2
NEW
3
-
General 160×160 — the min size; a grid track may stretch the tile, nothing inside scales.var(--sp-s0) — paddings.var(--sp-s20) — the corner radius by default.Left — alignment.
-
1
StartText Fill — the horizontal autolayout resizing; Hug — the vertical.var(--sp-s12) — side paddings, each side.var(--sp-s10) — top padding.var(--sp-s0) — the gap between the title and the subtitle. Any SP size can be set.Subtitle — hidden by default.Left / Top — the alignment; set what the design needs.Two modes per text line — Standard, a simple text; Expanded, up to two trailing slots after the text (any DS element, IconContainer by default) at var(--sp-s4) gaps.
-
2
DecorationContainer Hidden by default; any DS component can be placed inside.The example — the Tag inside the DecorateContainer; the container itself steps out of the tile: var(--sp-s8) above the top edge, var(--sp-s4) past the side edge. Negative instance offsets — the DecorateContainer contract.
-
3
BottomSlot 160×160 — the size; absolute position.Constraints left + right / top + bottom — the overlay stretches with the root: resizing changes the size of the slot itself, never its position.Fill — horizontal and vertical, for the ImageContainer inside the slot. The image has its own alignment within the container.
M
-
General 160×76 — the min size.The rest of the parameters are the same as for the L size.
-
1
StartText The same parameters as for the L size.
-
2
DecorationContainer The same parameters as for the L size.
-
3
ImageContainer 160×76 — the size; the rest is the same as for the L size.The recipe reseats the artwork for the wide crop (box 118 / bottom −28 / end −36) — nothing scales; the bleed is cut at the root edge.
S
-
General 76×76 — the min size.The rest of the parameters are the same as for the L size.
-
1
StartText The same parameters as for the L size.
-
2
DecorationContainer The same parameters as for the L size.
-
3
ImageContainer 76×76 — the size; the rest is the same as for the L size.The artwork bleeds past the end edge per its recipe (box 110 / bottom −28 / end −47); the bleed is cut at the root edge.
RTL
LTR
RTL
-
Mirrored Layout The title moves to the inline-end; the artwork recipe anchors logically (inset-inline-end), so the seat mirrors on its own.
-
Illustrations Mirror Under dir="rtl" every illustration mirrors with the layout: the plain artwork gains scaleX(-1) and a baked mirror inverts back — the vehicle always faces with the reading direction.
Animation
Press is the card family's pushItem, inherited from the customCard base — hold the tile to feel it. The demo is the component's own :active wiring; nothing is scripted.
-
Press / Release var(--component-push-item-press) — press, scale 100% → 95%.var(--component-push-item-release) — release, back to 100%.Only transform takes part — the press stays on the compositor.
-
Skeleton Shimmer var(--pattern-shimmer) — the Skeleton component's own sweep on the caption line; the tile animates nothing of its own.
-
Reduced Motion Handled at the token: motion.css zeroes every --component-* and --pattern-* inside prefers-reduced-motion: reduce — no local override.
-
Lottie A Lottie in the ImageContainer follows the primitive's contract (§ 6) and is blocked on the DS Lottie player decision.
Usage
Under construction
Accessibility
One tile = one button. The accessible name is the StartText content — the title, then the subtitle when shown, comma-joined, each line verbatim; the illustration is decorative and never announced.
1
2
-
1
Single Button The whole tile is ONE focusable element named by the visible StartText lines, verbatim — visual truncation (the ellipsis) never truncates the announcement. The artwork subtree is silent: aria-hidden="true" / importantForAccessibility="no" / isAccessibilityElement = false.
-
2
Skeleton Is Invisible TalkBack: removed from focus order entirely — nothing announced per tile, loading speaks once at list level. VoiceOver: skipped (isAccessibilityElement = false) — the rotor never lands on a shimmering placeholder. On web the specimen renders as a non-focusable <div>, never a named button.
-
No State Suffix The tile has no checked or expanded semantics; a service that cannot be opened is not rendered as a tile — there is no disabled announcement to design.
-
Decoration Joins The Name A decorated tile stays a single focus area: the decorator slots carry aria-hidden="true" and a meaningful decorator joins the host name — aria-label="Courier, new". The single-focus-area contract lives in DecorateContainer § 10.
-
Implementation Trap The name is computed from the visible StartText lines — no aria-label duplication of what the DOM already says: a hardcoded label would silently diverge from a renamed service. The decorated tile is the ONE exception, because its decorator meaning has no other way into the name.