Components
Voucher
A 144px ticket tile — a title, a description and an Apply action, light or dark, default or applied.
Figma description ·
VoucherOpen in Figma ↗This component has no description in Figma yet.
Props
import SwiftUI import EandTokens // Voucher: a fixed 144×144 ticket (r16). The outline, side notches and perforation are // ONE exported Figma path (28278:13819) — import it as a vector asset; don't redraw it. // Light = white ticket, dark = midnight-raised. Title title/xs over body/md, centred // (padding 16/8), then the button/lg "Apply" action (padding 16/12). struct Voucher: View { let title: String; let description: String var applied = false var onApply: () -> Void = {} var body: some View { VStack(spacing: 0) { VStack(spacing: 0) { Text(title).font(.system(size: EandTypography.titleXs.size, weight: EandTypography.titleXs.weight)) Text(description).font(.system(size: EandTypography.bodyMd.size)) } .foregroundColor(EandColor.textDefaultDefault) .multilineTextAlignment(.center) .padding(.vertical, EandSpacing.lg).padding(.horizontal, EandSpacing.sm) .frame(maxHeight: .infinity) Button(action: onApply) { HStack(spacing: EandSpacing.xs) { Text(applied ? "Applied" : "Apply") .font(.system(size: EandTypography.buttonLg.size, weight: EandTypography.buttonLg.weight)) Image(systemName: applied ? "checkmark" : "plus.circle.fill").font(.system(size: EandIcon.xl)) } .foregroundColor(applied ? EandColor.textPositiveSubtle : EandColor.buttonTertiaryTextMidnightDefault) } .disabled(applied) .padding(.vertical, EandSpacing.lg).padding(.horizontal, EandSpacing.md) } .frame(width: EandScale.scale144, height: EandScale.scale144) .background(Image("voucher-shape").renderingMode(.template).foregroundColor(EandColor.surfaceBaseInverse)) .clipShape(RoundedRectangle(cornerRadius: EandRadius.radius6)) } }
When to use
- Use to offer a promo code or voucher the user can apply at checkout, in a row of tiles.
- Don't use for a deal the user browses (use DealCard).
Anatomy
- Ticket — one exported shape with side notches and a perforation.
- Text —
titleintitle/xsoverdescriptioninbody/md, centred. - Action — "Apply" with an add glyph, which calls
onApply. Oncestate="applied", it reads "Applied" with a check, in green, and is disabled.
display="light" is the white ticket; display="dark" the midnight-raised one.
<Voucher title="20% off" description="above AED 60+" onApply={apply} />
<Voucher display="dark" state="applied" title="Free delivery" description="on orders over AED 100" />Deprecated
status is the V1.0 model: active becomes state="default" and redeemed becomes
state="applied". expired has no Figma counterpart; it renders the applied tile dimmed.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
description? | ReactNode | above AED 60+ | Second line under the title, e.g. "above AED 60+". |
display? | 'light' | 'dark' | light | |
onApply? | (() => void) | — | |
state? | 'default' | 'applied' | — | |
status? | 'active' | 'redeemed' | 'expired' | — | Deprecated. V1.0. active->Default, redeemed->Applied; expired dims the tile. |
title? | ReactNode | Title with 2 lines |
Design
Figma source: Voucher — etisalat Consumer App DSL V1.2
- A fixed 144 × 144 tile. The ticket fills
surface/base/inverse, orsurface/raised/midnightwhen dark. - Text block padding 16 × 8 (
spacing/lg,spacing/sm); action padding 16 × 12. - The action uses
button/lgwith a 24px glyph. Applied green istext/positive/subtleon light andtext/positive/mutedon dark, for contrast. - The Voucher page in Figma is still marked work in progress.