Recommendation
A centred 224px card that recommends one offer — logo, title, description and a single button — on glass or white.
RecommendationOpen in Figma ↗Use for
A self-contained card for surfacing a single personalized recommendation — a feature, service, or content item — with a branded icon, a short title, a supporting description, and a CTA button. Use in a horizontal carousel or as a standalone unit within a section when the goal is to prompt the user toward a specific action based on their context or usage.
Not for
Plan or product selling with pricing — use card-features variants for those. Category or service navigation — use service-card for that. Content that requires an image in the header — use card-info for that. Lists of items — use card-list for that. Any context where more than one CTA is needed.
Choosing
Set carousel=true when the card is part of a horizontally scrollable row — two cards are shown side by side with a 4px gap, each at 338px width, peeking the next item. Set carousel=false for a standalone full-width card at 353px.
Set inverse=true when the card sits on a dark or midnight surface — the background uses surface/glass/white/md (15% white glass), the title uses text/default/inverse (white), the description uses text/default/inverse-subtle (75% white), and the button uses scheme=inverse (white button, dark label). Set inverse=false on light surfaces — the background uses surface/base/default, text uses default dark tokens, and the button uses scheme=midnight (dark button, white label). Do not mix schemes — match inverse to the surrounding section surface.
Set direction=rtl for Arabic — the title and description use dir=auto and flip automatically. The button label also flips via dir=auto. Do not override text alignment manually.
Rules
The card is fixed at 224px height. In carousel mode each card is 338px wide; in standalone mode 353px wide. Do not resize the instance. The icon sits centered at the top of the card in a 32px container with border-radius/2 (8px) — do not replace it with a flat icon or image, and do not resize the container. The title uses title/md (20px semi-bold), centered, truncated with ellipsis — do not allow it to wrap beyond the available height. The description uses body/md (14px regular), centered, subtle color — it fills the remaining flex space and is also truncated. The CTA button is full-width, size=md (40px), primary style, centered at the bottom with 12px top padding. Do not remove the button or add a second one. All spacing values are tokenized — do not hard-code measurements.
import SwiftUI import EandTokens // Recommendation: 224pt (row-3), r20, padding 16, everything centred. inverse (default): // white glass 15% + blur over imagery, white primary md button. 32pt r8 icon, title/md // (2 lines), body/md description, CTA 12pt below. Carousel cards are 338 wide, gap 4. struct Recommendation: View { var body: some View { VStack(spacing: 0) { Image("rec-offers").resizable() .frame(width: EandIcon.icon2xl, height: EandIcon.icon2xl) .clipShape(RoundedRectangle(cornerRadius: EandRadius.radius3)) VStack(spacing: EandSpacing.xs) { Text("Recommended for you") .font(.system(size: EandTypography.titleMd.size, weight: EandTypography.titleMd.weight)) .foregroundColor(EandColor.textDefaultInverse).lineLimit(2) Text("Handpicked offers based on how you use e&.") .font(.system(size: EandTypography.bodyMd.size)) .foregroundColor(EandColor.textDefaultInverseSubtle) Spacer(minLength: 0) } .multilineTextAlignment(.center) .padding(.top, EandSpacing.md) InverseButton(title: "Explore", size: .md) {} // white fill, midnight label .padding(.top, EandSpacing.md) } .padding(EandSpacing.lg) .frame(maxWidth: .infinity).frame(height: EandSection.bodyHeightRow3) .background(EandColor.surfaceGlassWhiteMd) .background(.ultraThinMaterial) .clipShape(RoundedRectangle(cornerRadius: EandRadius.radius7)) } }
When to use
- Use to suggest one personalised offer or next step with a single clear action. The default
glass card sits on a dark or image backdrop;
inverse={false}gives a white card for light sections. - Don't use for a set of offers with prices or media (DealCard, ProductCard), or for a full-width campaign banner (Highlight).
Options
inverse(defaulttrue) — white glass with a backdrop blur, white text and an inverse primary button.falseis a white card with a midnight primary button.carousel— renders this card and each entry ofitemsas 338px cards, 4px apart, scrolling sideways so the next card peeks. Figma's default variant is the carousel; the component defaults to a single card, because a carousel needsitems.- Content —
iconis a 32px logo (a Smiles placeholder until you pass one;nullhides it).ctais the button label;nullhides the button.titleanddescriptiondefault to placeholder copy, so always pass your own.
import { Recommendation } from '@eand/react-design-system';
<Recommendation
carousel
title="Double data this weekend"
description="Get twice the data on your plan until Sunday."
cta="View offer"
items={[
{ title: 'Add a second line', description: 'Share your plan with family.', cta: 'Explore' },
]}
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
carousel? | boolean | false | Figma carousel — this card and items as 338-wide peeking cards. |
cta? | ReactNode | Explore | Figma button label. null hides the button. |
description? | ReactNode | Handpicked offers based on how you use etisalat. | Figma description-string. |
icon? | ReactNode | — | Figma visual-asset — a 32px logo. Smiles placeholder by default; null hides it. |
inverse? | boolean | true | Figma inverse — glass on a dark backdrop (default) vs white. |
items? | RecommendationItem[] | — | Further cards for carousel. |
onCta? | (() => void) | — | |
title? | ReactNode | Recommended for you | Figma title-string — two lines max. |
width? | string | number | — |
Design
Figma source: Recommendation — etisalat Consumer App DSL V1.2
- 224px tall (
row-3),border-radius/7(20px), padding 16 (spacing/lg), every element centred. - A 32px logo (
icon/2xl) atborder-radius/3; 12 below it (spacing/md), the title intitle/md(two lines at most) and the description inbody/md, 4 apart (spacing/xs); then a primary md button, 12 above it. inverse:surface/glass/white/mdwith a 20px backdrop blur, titletext/default/inverse, descriptiontext/default/inverse-subtle. White:surface/base/inverse,text/default/defaultandtext/default/subtle.- Carousel cards are 338px wide in a 353px slot, gap
spacing/xs. The width has no token.