Design System
Components

ActionBlock

The content of a CTA bar — status ribbon, price line, consent checkbox and actions — without its surface.

Figma description · .action-blockOpen in Figma ↗

This component has no description in Figma yet.

Payment method saved
Total amountAED 1,250.00
Props
import SwiftUI
import EandTokens

// .action-block payment=true: the payment summary and the lg primary button share one row
// half and half (gap 2), padded 16/20/0. Without payment the button group pads 20/20/0.
// PaymentRow: 40pt r8 tile on surface/base/default, body/md number over a tertiary "Change".
struct ActionBlock: View {
  var body: some View {
    VStack(spacing: 0) {
      PriceLine(label: "Total amount", value: "AED 1,250")
      HStack(spacing: EandSpacing.spacing2xs) {
        HStack(spacing: EandSpacing.md) {
          Image("card-visa").resizable().scaledToFit()
            .frame(width: EandScale.scale40, height: EandScale.scale40)
            .background(EandColor.surfaceBaseDefault)
            .clipShape(RoundedRectangle(cornerRadius: EandRadius.radius3))
          VStack(alignment: .leading, spacing: EandSpacing.xs) {
            Text("•••• 4326").font(.system(size: EandTypography.bodyMd.size)).lineLimit(1)
            Text("Change")
              .font(.system(size: EandTypography.buttonMd.size, weight: EandTypography.buttonMd.weight))
              .foregroundColor(EandColor.buttonTertiaryTextBrandDefault)
          }
        }
        .frame(maxWidth: .infinity, alignment: .leading)
        EandButton(title: "Pay now") {}.frame(maxWidth: .infinity)
      }
      .padding(.top, EandSpacing.lg).padding(.horizontal, EandSpacing.xl)
    }
  }
}

When to use

  • Use when you need the closing actions of a flow step on a surface you already provide. For the standard sticky footer, use the CTA Bar (CtaFooter): it renders an ActionBlock on its white surface with a shadow and the home indicator.
  • Don't use for actions inside page content; use a Button or a ButtonGroup there.

Anatomy

The slots stack top to bottom, as in Figma. Only actions is required.

  1. ribbon — a full-width StatusRibbon.
  2. price — the fields of a PriceLine: { label, value, actionLabel?, onAction?, actionIcon? }.
  3. terms — a ConsentCheckbox. Its state stays with you.
  4. actions — a ButtonGroup or a block Button. With payment (a PaymentRow), the payment summary and the actions sit side by side, half the width each.

ActionBlock has no bottom padding. In the CTA Bar the 34px home indicator supplies it; on your own surface, add the bottom spacing yourself.

import { useState } from 'react';
import { ActionBlock, Button, ButtonGroup, ConsentCheckbox } from '@eand/react-design-system';

function CheckoutActions() {
  const [agreed, setAgreed] = useState(false);
  return (
    <ActionBlock
      price={{ label: 'Total', value: 'AED 125.00' }}
      terms={
        <ConsentCheckbox
          checked={agreed}
          onChange={(e) => setAgreed(e.currentTarget.checked)}
          prefix="Agree to the"
          links={[{ label: 'Terms & Conditions', href: '/terms' }]}
        />
      }
      actions={<ButtonGroup primary={<Button size="lg" block disabled={!agreed}>Pay now</Button>} />}
    />
  );
}

Props

PropTypeDefaultDescription
actionsReactNode—CTA buttons (use <ButtonGroup/> or a block <Button/>).
payment?ReactNode—Payment-method summary (use <PaymentRow/>); renders beside the actions, half each.
price?CtaFooterPrice—Price summary, rendered as a <PriceLine/>.
ribbon?ReactNode—Status strip across the very top (use <StatusRibbon/>).
terms?ReactNode—Checkbox line — pass a <ConsentCheckbox/> (or a <Checkbox/>) so state stays with the caller.

Design

Figma source: .action-block — etisalat Consumer App DSL V1.2

  • Order: status ribbon, price line, checkbox line, actions.
  • Checkbox line: padding 16/20/0 (spacing/lg, spacing/xl).
  • Actions without payment: padding 20/20/0 (spacing/xl), the padding of .button-group-vertical.
  • Actions with payment: padding 16/20/0, gap 2 (spacing/2xs); the payment row and the button take half each.
  • Every row is a flex row with symmetric or logical padding, so the block mirrors in RTL.

On this page