Design System
Components

GeneralCard

A fixed 224px tile with a centred title, an image and an optional badge, for grids and carousels.

Figma description · General-cardOpen in Figma ↗

Use for

A flexible media card for surfacing content, features, or navigational entry points where an image or icon is the primary visual and a short title supports it. Use in grid or carousel section layouts when the content doesn't have a price or service-bundle structure that would require a more specific card variant.

Not for

Plan or subscription content with pricing — use plans-mini or card-features-package. Product items with a product image and price — use card-features-product. Category entry points — use card-features-category. Content that requires body text, descriptions, or multiple CTAs — this card supports a title and badge only.

Choosing

Set surface=default when the card sits in a light section context. Set surface=inverse when it sits in a dark section context. Do not choose surface for visual variety — match it to the surrounding section surface. Both variants share the same internal structure; only the surface, text, and color tokens differ.

Set carousel=true for a scrollable horizontal layout; carousel=false for a fixed grid layout. In carousel mode the card width is narrower (147px); in grid mode it is wider (166px) to fill the grid slot — do not manually resize to compensate.

Set top-alignment=true to pin the title to the top of the card with the image centered below. Set top-alignment=false to pin the title to the top and allow the image to sit vertically centered in the remaining space. Use top-alignment when the title is the primary read and the image is supporting. Use bottom-alignment when the image carries more visual weight.

Set size to control the media slot: sm for supporting visuals where imagery is secondary, md for a balanced media-and-text read, lg when the image is the primary communication layer. Do not pick size for aesthetic reasons — match it to the content's role in the layout.

Set badge to show a badges-offers or badges-status tag when there is an active offer or status to surface. The badge sits at the bottom-left of the card inside the .badge-placement slot at 12px padding. Set badge off when there is no offer or status to show.

Set direction=rtl for Arabic. The title uses centered alignment and will reflow correctly; the badge placement mirrors to the bottom-right.

Rules

The title uses title/sm (16px semi-bold), centered, maximum 2 lines. Do not allow it to overflow beyond 2 lines — truncate or shorten copy to fit. The media slot is absolutely positioned and fills the card — do not move or reposition the image layer manually. All spacing and sizing values are tokenized — do not hard-code any measurements. Card height is fixed at 224px across all variants. Do not resize the instance height. For RTL, set direction=rtl at the component level — do not override text alignment or badge position manually.

Watch live sport on eLife
20% off
Smart home starter kit
New
Props
import SwiftUI
import EandTokens

// General-card: a fixed 224pt (row-3) tile, r20, clipped; 166 wide in a two-up grid.
// surface default = DARK (surface/raised/midnight, inverse ink); inverse = white.
// Title title/sm, centred, 2 lines, padded 24/12/0. Image sm 64 (at y 104) · md 128 ·
// lg 224 full-bleed. Badge slot along the bottom (top with topAlignment).
struct GeneralCard: View {
  let title: String; let image: Image
  var body: some View {
    ZStack(alignment: .top) {
      image.resizable().scaledToFit()
        .frame(width: EandScale.scale64, height: EandScale.scale64)
        .offset(y: 104)
      Text(title)
        .font(.system(size: EandTypography.titleSm.size, weight: EandTypography.titleSm.weight))
        .multilineTextAlignment(.center).lineLimit(2)
        .padding(.top, EandSpacing.spacing2xl).padding(.horizontal, EandSpacing.md)
      VStack { Spacer(); HStack { OfferBadge(text: "20% off"); Spacer() } }
        .padding(EandSpacing.md)
    }
    .foregroundColor(EandColor.textDefaultInverse)
    .frame(width: EandSection.bodyWidthCol12, height: EandSection.bodyHeightRow3)
    .background(EandColor.surfaceRaisedMidnight)
    .clipShape(RoundedRectangle(cornerRadius: EandRadius.radius7))
  }
}

When to use

  • Use for category or offer tiles inside a Section: a short title (two lines at most) and a visual, in a two-up grid or a carousel.
  • Don't use for content with body copy and an action; that is Card. Not for plans or products with prices (PlanCard, ProductCard), and not for full-width campaign banners (Highlight).

surface follows the published Figma naming: default is the dark card and inverse is the white one. That is the reverse of Card. The label is awaiting design confirmation.

Options

PropValuesEffect
sizesm · md · lgImage 64px, 128px, or 224px full-bleed
topAlignmentfalse · truetrue moves the title to the bottom and the image and badge to the top
carouselfalse · truetrue fixes the width at 147px; otherwise the card fills its grid slot
badgePlacementstart · center · endBadge alignment; mirrors in RTL

topAlignment follows the published symbol. The symbol's description text says the reverse, which is logged as a design question.

Pass a Badge as badge. image takes a URL or your own node. imageAlt defaults to an empty string, which marks the image as decorative; set it when the image carries meaning.

Props

PropTypeDefaultDescription
titleReactNode—
badge?ReactNode—A Badge (offer or status), placed 12px in from the corner.
badgePlacement?'end' | 'start' | 'center'startBadge alignment (Figma .badge-placement Left | Center | Right, mirrored in RTL).
carousel?booleanfalseCarousel cell (147 wide) instead of a grid cell that fills its slot.
image?ReactNode—Image URL, or your own node (it is sized to the media box).
imageAlt?string—
size?'lg' | 'md' | 'sm'smMedia size (Figma size): sm 64 · md 128 · lg 224 full-bleed.
surface?'default' | 'inverse'defaultFigma surface: default is the DARK card, inverse the white one (as published).
topAlignment?booleanfalseFigma top-alignment: true = image and badge at the top, title at the bottom.

Design

Figma source: General-card — etisalat Consumer App DSL V1.2

  • 224px tall (rem/14), border-radius/7 (20px), clipped. In a two-up grid it is 166px wide (section/body/width/col-12); the 147px carousel width has no token.
  • Title title/sm, centred, two lines at most. Padding 24/12/0 (spacing/2xl, spacing/md), or 0/12/24 with topAlignment.
  • Fill: default is surface/raised/midnight with text/default/inverse; inverse is surface/base/inverse with text/default/default.
  • The badge sits in .badge-placement: padding 12 (spacing/md), gap 4 (spacing/xs).
  • Images are placed by constraints: sm 104px from the top (56px with topAlignment), md flush to the edge opposite the title, lg filling the card.

On this page