Files
xrpl-dev-portal/shared/patterns/LinkTextCard/README.md
Calvin a4b1925b31 [feat] Add LinkTextCard and LinkTextDirectory Components (#3501)
* adding linktextcard + linktextdirectory

* adding dark mode

* code review clean up

* code review comments
2026-02-17 12:21:10 -08:00

6.6 KiB

LinkTextCard Component

A numbered card component displaying a heading, description, and call-to-action buttons.

Overview

LinkTextCard is a pattern component designed for sequential content presentation. Each card displays a numbered label (01, 02, 03...), a heading, description text, and up to 2 action buttons. Perfect for feature lists, step-by-step guides, or numbered content sections.

Features

  • Sequential Numbering: Auto-increments based on index prop with zero-padding (01, 02, 03...)
  • Minimal HTML Structure: Flat DOM hierarchy for optimal performance
  • ButtonGroup Integration: Supports up to 2 buttons (Primary + Tertiary layout)
  • Fixed Button Color: Green buttons for brand consistency
  • Light/Dark Mode: Full theming support
  • Responsive Design: Adaptive spacing and typography across breakpoints
  • Top Divider: Border-top styling with theme-aware colors

Usage

Basic Usage (2 Buttons)

<LinkTextCard
  index={0}
  heading="Fast Settlement and Low Fees"
  description="Settle transactions in 3-5 seconds for a fraction of a cent, ideal for large-scale, high-volume RWA tokenization"
  buttons={[
    { label: "Get Started", href: "/start" },
    { label: "Learn More", href: "/docs" }
  ]}
/>

Single Button

<LinkTextCard
  index={1}
  heading="Secure and Reliable"
  description="Built on proven blockchain technology with enterprise-grade security"
  buttons={[
    { label: "Read Documentation", href: "/docs" }
  ]}
/>

With Click Handlers

<LinkTextCard
  index={2}
  heading="Developer Friendly"
  description="Comprehensive APIs and SDKs for seamless integration"
  buttons={[
    { label: "View API", onClick: () => navigate('/api') },
    { label: "See Examples", href: "/examples" }
  ]}
/>

In a List

{features.map((feature, index) => (
  <LinkTextCard
    key={feature.id}
    index={index}
    heading={feature.heading}
    description={feature.description}
    buttons={feature.buttons}
  />
))}

Props

LinkTextCardProps

Prop Type Default Description
index number Required Card index for numbering (displays as index + 1)
heading string Required Main heading text
description string Required Description/body text
buttons ButtonConfig[] Required Array of button configurations (max 2)
className string - Additional CSS classes

ButtonConfig (from ButtonGroup)

Prop Type Default Description
label string Required Button text
href string - Link destination (renders as anchor)
onClick () => void - Click handler (renders as button)
forceColor boolean false Force color regardless of theme

Note: Only the first 2 buttons will be rendered. Button color is fixed to 'green'.

Component Structure

<li className="bds-link-text-card">
  <div className="bds-link-text-card__header">
    <p className="body-l">01</p>
    <h5 className="sh-lg-l">Fast Settlement and Low Fees</h5>
  </div>
  <div className="bds-link-text-card__content">
    <p className="body-l">Settle transactions in 3-5 seconds...</p>
    <ButtonGroup buttons={[...]} color="green" />
  </div>
</li>

Key Design Decisions:

  • List Item Element: Renders as <li> for semantic list markup
  • Two-Section Layout: Header (number + heading) and Content (description + buttons)
  • Border-Top Divider: Applied directly to container (no separate element)
  • Typography Classes: Uses existing body-l and sh-lg-l classes
  • Flexbox Gap: Responsive spacing via gap property
  • 75% Width at MD+: Content is constrained to 75% width on tablet and desktop

Responsive Spacing

Breakpoint Card Gap Header Gap Content Gap Padding Top Padding Bottom
Base (< 576px) 24px 8px 16px 8px 24px
MD (576px - 991px) 32px 12px 24px 12px 32px
LG (≥ 992px) 40px 16px 32px 16px 40px

Card Gap: Space between header and content sections Header Gap: Space between number and heading Content Gap: Space between description and ButtonGroup Padding Top: Space from top border to content Padding Bottom: Space after content (removed on last card)

Styling

CSS Classes

  • .bds-link-text-card - Main list item container with flexbox layout and border-top
  • .bds-link-text-card__header - Header section (number + heading)
  • .bds-link-text-card__content - Content section (description + buttons)
  • Typography utilities: body-l, sh-lg-l

Color Variables

  • $gray-300 - Border color (light mode)
  • $gray-500 - Number text color
  • $white - Text color in dark mode (applied to entire card)

Number Formatting

The component automatically formats numbers with zero-padding:

index: 0   "01"
index: 1   "02"
index: 9   "10"
index: 99  "100"

Button Behavior

1-2 Buttons

  • 1 button: Renders as primary button
  • 2 buttons: First as primary, second as tertiary

3+ Buttons

If more than 2 buttons are passed, only the first 2 will be rendered (automatically sliced).

Files

  • LinkTextCard.tsx - React component with TypeScript
  • LinkTextCard.scss - Minimal SCSS with BEM naming
  • index.ts - Barrel exports
  • README.md - This file
  • ButtonGroup: Used for rendering action buttons
  • Button: Atomic button component used by ButtonGroup

Import

import { LinkTextCard } from 'shared/patterns/LinkTextCard';
// or
import { LinkTextCard, type LinkTextCardProps } from 'shared/patterns/LinkTextCard';

Design System

Part of the Brand Design System (BDS) with bds- namespace prefix.

Best Practices

  1. Use Sequential Indices: Pass indices 0, 1, 2... for proper numbering
  2. Limit Buttons: Design works best with 1-2 buttons
  3. Clear Descriptions: Keep descriptions concise but informative
  4. Consistent Length: Try to keep similar text lengths across cards in a group

Accessibility

  • Semantic HTML: Renders as <li> for use within <ul> lists
  • Heading hierarchy: Uses <h5> for card headings (adjust based on parent context)
  • Button labels should be descriptive
  • Maintains focus order: number → heading → description → buttons

Note on Heading Semantics: The component uses <h5> inside a list item, which is acceptable when the parent section has appropriate heading hierarchy. The heading level can be adjusted based on your specific use case.