* BDS component polish: link visibility, static cards, uniform CTAs Component-level fixes and refinements across the 2026 brand components. Accessibility / contrast - StandardCard: pin description link colors. Every card variant has a light background in both themes, so theme-level link colors were wrong inside it — dark mode painted plain anchors white and BdsLink lilac-300, both of which wash out on a pale card. Links (including :visited) now use the card's own text color with an underline carrying the affordance; hover uses lilac-500, which clears 4.5:1 on all four card backgrounds. - Breadcrumbs: point the open dropdown menu at the breadcrumb color tokens so the trail, trigger, and menu read as one color in both themes, and give dark mode gray-6 (7.41:1, matching light mode's 7.23:1). Interaction - CardOffgrid: drop every hover affordance when a card has neither href nor onClick. Static cards no longer get a pointer cursor, the color-wipe overlay, or a pressed state — the tokenization and trading carousels pass link-less cards and were advertising a click target that did not exist. - CarouselFeatured: add a 'fade' transition alongside the default 'slide', for decks whose slides share a heading. Inactive slides are now inert, keeping focus and pointer events out of them in both styles. - Add a bds-reduced-motion mixin so components can collapse motion to an instant state change. Design consistency - ButtonGroup: add forceVariant and forceNoPadding overrides, letting a section opt out of the count-based variant defaults and render one uniform treatment. Existing consumers are unaffected. - FeatureTwoColumn: render every link as a tertiary button regardless of count, flush with the title and description. - CardImage: render an all-bullet subtitle as a real <ul> so wrapped text hangs under the first character and screen readers announce it as a list. - docs: give the node-installation card descriptions a paragraph break before their "Learn More" link. Dependencies - Bump @codemirror/state and view, add lang-javascript, lang-json, and lint, with overrides pinning state/view to one copy. Docs updated alongside each component. Built CSS regenerated with the production script to match the committed artifact's minified format. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * ButtonGroup: don't strip padding from forced filled variants `noPadding` was derived as `forceNoPadding || isMultiButton`, which was safe while the 3+ block layout was always tertiary. `forceVariant` also accepts `primary` and `secondary`, so a 3-button group forcing a filled variant had `padding: 0 !important` (Button.scss) applied with no way to opt out. Tie the implied no-padding to the resolved variant being tertiary. Behavior is unchanged for every caller that doesn't pass `forceVariant`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Stacked hero variant, fade-by-default carousel, component docs Layout - HeaderHeroPrimaryMedia: add a `stacked` prop that puts the headline, subtitle, and buttons in one column (full width at base, 7/8 at md, 9/12 at lg) instead of the default headline-left / CTA-right split. The headline and CTA block bottom-align against each other in the two-column layout, so the stacked variant undoes that. Both arrangements now share the same headline and CTA elements, so they can't drift apart. Used on the docs landing hero. Motion - CarouselFeatured: make `fade` the default transition. Slides that share a heading are the common case, and a horizontal wipe drags the identical heading across the screen only to set it back down. `slide` is now opt-in for decks whose panels are genuinely distinct. Nudge the crossfade to 260ms in / 200ms out. The home page carousel opts into fade explicitly; developer-funding now inherits it. Fixes - CardTextIconCard: pass `headingAs` through to `cardContent`, which was accepting the prop but never receiving it. Docs - Expand the Button, CardImage, CardTextIcon, PageGrid, CalloutMediaBanner, LogoSquareGrid, and HeaderHeroPrimaryMedia references. Built CSS regenerated with the production script. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
11 KiB
CardOffgrid Component - Usage Guide
Overview
CardOffgrid is a feature highlight card component designed to showcase key capabilities, features, or resources. It combines an icon, title, and description in a visually engaging, interactive card format with smooth hover animations.
Use CardOffgrid when:
- Highlighting key features or capabilities
- Creating feature grids or showcases
- Linking to important documentation or resources
- Presenting product/service highlights
Don't use CardOffgrid for:
- Simple content cards (use standard Bootstrap cards)
- Navigation items (use navigation components)
- Data display (use tables or data components)
- Long-form content (use article/page layouts)
When to Use Each Variant
Neutral Variant (variant="neutral")
Use for:
- General feature highlights
- Standard content cards
- Secondary or supporting features
- When you want subtle, professional presentation
Example use cases:
- Documentation sections
- Feature lists
- Service offerings
- Standard informational cards
Green Variant (variant="green")
Use for:
- Primary or featured highlights
- Call-to-action cards
- Important announcements
- Brand-emphasized content
Example use cases:
- Hero feature cards
- Primary CTAs
- Featured resources
- Branded highlights
Content Best Practices
Title Guidelines
✅ Do:
- Keep titles concise (1-3 words ideal)
- Use line breaks (
\n) for multi-word titles when needed - Make titles action-oriented or descriptive
- Examples: "Onchain Metadata", "Token\nManagement", "Cross-Chain\nBridges"
❌ Don't:
- Write long sentences as titles
- Use more than 2 lines
- Include punctuation (periods, commas)
- Make titles too generic ("Feature", "Service")
Description Guidelines
✅ Do:
- Write 1-2 sentences (15-25 words ideal)
- Focus on benefits or key information
- Use clear, simple language
- Keep descriptions scannable
❌ Don't:
- Write paragraphs (save for full pages)
- Use jargon without context
- Include multiple ideas in one description
- Make descriptions too short (< 10 words) or too long (> 40 words)
Icon Guidelines
✅ Do:
- Use SVG icons for crisp rendering
- Choose icons that represent the feature clearly
- Ensure icons are recognizable at 68×68px
- Use consistent icon style across cards
❌ Don't:
- Use low-resolution raster images
- Choose overly complex icons
- Mix icon styles within a single grid
- Use icons that don't relate to the content
Interaction Patterns
Using onClick vs href
Use onClick when:
- Triggering JavaScript actions (modals, analytics, state changes)
- Opening external links in new tabs
- Performing client-side navigation
- Handling complex interactions
<CardOffgrid
variant="neutral"
icon={<AnalyticsIcon />}
title="View Analytics"
description="See detailed usage statistics and insights."
onClick={() => {
trackEvent('analytics_viewed');
openModal('analytics');
}}
/>
Use href when:
- Navigating to internal pages
- Linking to documentation
- Simple page navigation
- SEO-friendly links
<CardOffgrid
variant="green"
icon="/icons/docs.svg"
title="API\nReference"
description="Complete API documentation and examples."
href="/docs/api"
/>
Static (Presentational) Cards
Omit both onClick and href to render a purely presentational card. It has no
click target, so the component drops every interactive affordance: no pointer
cursor, no hover color wipe, and no pressed state. It renders as a plain <div>
and isn't focusable or announced as a control.
Use this for cards that only communicate information — e.g. a "why XRPL" feature carousel where none of the cards link anywhere.
<CardOffgrid
variant="green"
icon="/icons/metadata.svg"
title="Onchain Metadata"
description="Easily store key asset information."
/>
Disabled State
Use disabled when:
- Feature is coming soon
- Feature requires authentication
- Feature is temporarily unavailable
- You want to show but not allow interaction
<CardOffgrid
variant="neutral"
icon={<BetaIcon />}
title="Coming\nSoon"
description="This feature will be available in the next release."
disabled
/>
Layout Best Practices
Grid Layouts
Recommended grid patterns:
// 2-column grid (desktop)
<div className="row">
<div className="col-md-6 mb-4">
<CardOffgrid {...props1} />
</div>
<div className="col-md-6 mb-4">
<CardOffgrid {...props2} />
</div>
</div>
// 3-column grid (desktop)
<div className="row">
{cards.map(card => (
<div key={card.id} className="col-md-4 mb-4">
<CardOffgrid {...card} />
</div>
))}
</div>
Spacing:
- Use Bootstrap spacing utilities (
mb-4,mb-5) between cards - Maintain consistent spacing in grids
- Cards are responsive and stack on mobile automatically
Single Card Usage
For hero sections or featured highlights:
<div className="d-flex justify-content-center">
<CardOffgrid
variant="green"
icon={<FeaturedIcon />}
title="New Feature"
description="Introducing our latest capability..."
href="/features/new"
/>
</div>
Accessibility Best Practices
Semantic HTML
The component automatically renders as:
<button>when usingonClick<a>when usinghref<div>when neither is provided (static card — not focusable, not announced as a control)
This ensures proper semantic meaning for screen readers.
Keyboard Navigation
✅ Always test:
- Tab navigation moves focus to cards
- Enter/Space activates cards
- Focus ring is clearly visible
- Focus order follows logical reading order
Screen Reader Content
✅ Ensure:
- Titles are descriptive and unique
- Descriptions provide context
- Icons have appropriate
aria-hidden="true"(handled automatically) - Disabled cards communicate their state
Color Contrast
All variants meet WCAG AA standards:
- Dark mode: White text on colored backgrounds
- Light mode: Dark text on light backgrounds
- Focus rings provide sufficient contrast
Common Patterns
Feature Showcase Grid
const features = [
{
variant: 'green',
icon: <TokenIcon />,
title: 'Token\nManagement',
description: 'Create and manage fungible and non-fungible tokens.',
href: '/docs/tokens'
},
{
variant: 'neutral',
icon: <MetadataIcon />,
title: 'Onchain\nMetadata',
description: 'Store key asset information using simple APIs.',
href: '/docs/metadata'
},
// ... more features
];
<div className="row">
{features.map((feature, index) => (
<div key={index} className="col-md-4 mb-4">
<CardOffgrid {...feature} />
</div>
))}
</div>
Mixed Variants for Hierarchy
Use green variant for primary features, neutral for supporting:
<div className="row">
<div className="col-md-6 mb-4">
<CardOffgrid
variant="green" // Primary feature
icon={<PrimaryIcon />}
title="Main Feature"
description="Our flagship capability..."
href="/feature/main"
/>
</div>
<div className="col-md-6 mb-4">
<CardOffgrid
variant="neutral" // Supporting feature
icon={<SupportIcon />}
title="Supporting Feature"
description="Complementary capability..."
href="/feature/support"
/>
</div>
</div>
Coming Soon Pattern
<CardOffgrid
variant="neutral"
icon={<ComingSoonIcon />}
title="Coming\nSoon"
description="This feature is currently in development and will be available soon."
disabled
/>
Performance Considerations
Icon Optimization
✅ Best practices:
- Use SVG React components (inlined) for small icons
- Use optimized SVG files for image icons
- Avoid large raster images
- Consider lazy loading for below-the-fold cards
Rendering Performance
- Cards are lightweight components
- Hover animations use CSS transforms (GPU-accelerated)
- No heavy JavaScript calculations
- Suitable for grids with 10+ cards
Troubleshooting
Common Issues
Card not clickable:
- Ensure
onClickorhrefis provided - Check that
disabledis not set totrue - Verify no parent element is blocking pointer events
Icon not displaying:
- Verify icon path is correct (if using string)
- Check icon component is properly imported
- Ensure icon fits within 68×68px bounds
Hover animation not working:
- Confirm the card has an
onClickorhref— static cards intentionally have no hover animation - Check browser supports CSS
clip-path - Verify no conflicting CSS is overriding transitions
- Test in different browsers
Focus ring not visible:
- Ensure keyboard navigation (Tab key)
- Check focus ring color contrasts with background
- Verify
outline-offset: 2pxis applied
Design System Integration
Color Tokens
All colors reference styles/_colors.scss:
- Dark mode (default): Uses
$gray-500,$gray-400,$green-300,$green-200 - Light mode (
html.light): Uses$gray-200,$gray-300,$green-200,$green-300
Typography
- Title: Booton Light, 32px, -1px letter-spacing
- Description: Booton Light, 18px, -0.5px letter-spacing
Spacing
- Card padding: 24px
- Content gap: 40px (between title and description)
- Icon container: 84×84px
Figma References
- Light Mode Colors: Figma Design - Light Mode
- Dark Mode Colors: Figma Design - Dark Mode
- Animation Specs: Figma Design - Storyboard
Component API
interface CardOffgridProps {
/** Color variant: 'neutral' (default) or 'green' */
variant?: 'neutral' | 'green';
/** Icon element (ReactNode) or image path (string) */
icon: React.ReactNode | string;
/** Card title - use \n for line breaks */
title: string;
/** Card description text (1-2 sentences) */
description: string;
/** Click handler - renders as <button> */
onClick?: () => void;
/** Link destination - renders as <a> */
href?: string;
/** Disabled state - prevents interaction */
disabled?: boolean;
/** Additional CSS classes */
className?: string;
}
Quick Reference
| Use Case | Variant | Interaction |
|---|---|---|
| Standard feature | neutral |
href or onClick |
| Primary feature | green |
href or onClick |
| Coming soon | neutral |
disabled |
| Feature grid | Mix both | href preferred |
| Hero section | green |
href |
Examples
See the CardOffgrid Showcase for live examples and interactive demos.