Data Display
Data display components use various bases depending on their interactivity. Most inherit from BaseStatic for pure presentation, BaseMedia for images, or BaseDisclosure for expandable content.
Card
Base: BaseContainer (static) or BaseInteractive (when onKevlarAction is provided)
States (static): idle
States (interactive): idle, hover, focused, pressed, skeleton, selected, disabled
Dev-fill slots (interactive):
onKevlarAction— click handler (makes the card interactive)touch.onLongPress,touch.onSwipe
Key behavior: Static by default. When onKevlarAction is provided, the card becomes a clickable interactive element with full BaseInteractive behavior. Skeleton state shows a shimmer placeholder. Selected state adds an outline.
import { Card, Text } from './kevlar';
{/* Static card */}
<Card>
<Text>Static content</Text>
</Card>
{/* Interactive card */}
<Card
onKevlarAction={async () => { router.push('/item/123'); }}
announce={{ loading: 'Opening...', success: 'Opened', error: 'Failed to open' }}
>
<Text>Click to view details</Text>
</Card>Image
Base: BaseMedia
States: idle, loading, loaded, error
Dev-fill slots:
alt— alt text (required, or usebadly_skip_alt_text_and_hurt_accessibility)width+heightoraspectRatio(required, or usebadly_allow_layout_shift_and_dont_define_size)network.onFast,network.onSlow,network.onOfflinefallback.onError— what to show when image fails to load
Key behavior: Network-adaptive loading strategy and quality selection. LQIP/blurhash placeholder during loading. Fade-in reveal on load. CLS prevention through required dimensions.
import { Image } from './kevlar';
<Image
src="/hero.jpg"
alt="Mountain landscape at sunset"
width={1200}
height={600}
/>Avatar
Base: BaseMedia (with image) or BaseStatic (initials/icon)
States (with image): idle, loading, loaded, error
States (initials/icon): idle
Dev-fill slots:
alt— alt text for image avatars (required, or use shame prop)name— used to generate initials fallback
Key behavior: Attempts to load the image source. On error, falls back to initials (from name) or a default icon. Circle shape by default.
import { Avatar } from './kevlar';
<Avatar
src="/avatars/user-123.jpg"
alt="Jane Doe"
name="Jane Doe"
/>
{/* Initials fallback */}
<Avatar name="Jane Doe" />Badge
Base: BaseStatic
States: idle
Dev-fill slots: None (purely presentational)
Key behavior: Static label element. No interaction states. Screen reader reads the text content naturally. Color variants are defined in the base.
import { Badge } from './kevlar';
<Badge color="green">Active</Badge>
<Badge color="red">Expired</Badge>Accordion
Base: BaseDisclosure (items) + BaseContainer (wrapper)
States: idle, hover, focused, expanded, collapsed, disabled
Dev-fill slots:
onKevlarAction— expand/collapse handlerannounce.expanded/announce.collapsed
Key behavior: role="region" with aria-labelledby pointing to the trigger. Arrow Up/Down navigate between accordion items. Enter/Space toggles expand/collapse. Supports single or multiple items open at once.
Validation: Accordion.Item must be inside an Accordion wrapper.
import { Accordion } from './kevlar';
<Accordion>
<Accordion.Item value="faq-1">
<Accordion.Control>How does billing work?</Accordion.Control>
<Accordion.Panel>
We bill monthly based on usage.
</Accordion.Panel>
</Accordion.Item>
<Accordion.Item value="faq-2">
<Accordion.Control>Can I cancel anytime?</Accordion.Control>
<Accordion.Panel>
Yes, you can cancel at any time.
</Accordion.Panel>
</Accordion.Item>
</Accordion>Spoiler
Base: BaseDisclosure
States: idle, expanded, collapsed
Dev-fill slots:
maxHeight— height before content is clippedshowLabel/hideLabel— toggle button textannounce.expanded/announce.collapsed
Key behavior: Clips content beyond maxHeight and shows a “Show more” button. The toggle button follows BaseInteractive behavior. Animation respects prefers-reduced-motion.
import { Spoiler } from './kevlar';
<Spoiler maxHeight={120} showLabel="Show more" hideLabel="Show less">
<Text>Long content that may be clipped...</Text>
</Spoiler>Indicator
Base: BaseStatic
States: idle
Dev-fill slots: None (purely decorative overlay)
Key behavior: Renders a small badge/dot at a corner of its child element. Used for notification counts, online status, etc. aria-hidden="true" on the indicator itself — use aria-label on the parent to convey the information to screen readers.
import { Indicator, Avatar } from './kevlar';
<Indicator label="3" color="red">
<Avatar src="/avatar.jpg" alt="User with 3 notifications" />
</Indicator>ColorSwatch
Base: BaseStatic
States: idle
Dev-fill slots: None
Key behavior: Displays a color sample. aria-label should describe the color for screen readers (e.g., “Brand blue, #228be6”).
import { ColorSwatch } from './kevlar';
<ColorSwatch color="#228be6" aria-label="Brand blue" />Kbd
Base: BaseStatic
States: idle
Dev-fill slots: None
Key behavior: Displays a keyboard key visual. Purely presentational. Screen reader reads the text content.
import { Kbd } from './kevlar';
<Kbd>Ctrl</Kbd> + <Kbd>K</Kbd>NumberFormatter
Base: BaseStatic
States: idle
Dev-fill slots: None
Key behavior: Formats numbers with locale-aware separators, currency symbols, and units. Purely presentational. No ARIA concerns beyond readable text.
import { NumberFormatter } from './kevlar';
<NumberFormatter value={1234567} thousandSeparator="," prefix="$" />ThemeIcon
Base: BaseStatic
States: idle
Dev-fill slots: None
Key behavior: Renders an icon inside a themed container (colored circle/square). aria-hidden="true" — the icon is decorative. Use alongside text that conveys the meaning.
import { ThemeIcon } from './kevlar';
<ThemeIcon color="blue" size="lg">
<CheckIcon />
</ThemeIcon>OverflowList
Base: BaseStatic + BaseInteractive (for the overflow button)
States: idle
Dev-fill slots:
onOverflow— how to display overflowed items (“+3 more” button, dropdown)
Key behavior: Renders items horizontally. Items that do not fit are hidden and represented by an overflow indicator. Resizes reactively. The overflow button opens a popover or menu with the hidden items.
import { OverflowList } from './kevlar';
<OverflowList>
<Badge>Tag 1</Badge>
<Badge>Tag 2</Badge>
<Badge>Tag 3</Badge>
<Badge>Tag 4</Badge>
<Badge>Tag 5</Badge>
</OverflowList>Timeline
Base: BaseStatic or BaseNavigation (when interactive)
States (static): idle
States (interactive): idle, hover, focused, active, disabled
Dev-fill slots (interactive):
onKevlarAction— item click handler
Key behavior: Vertical timeline with items. Items can be static (display only) or interactive (clickable to navigate/expand). Active item is highlighted. Screen reader reads items in order.
import { Timeline } from './kevlar';
<Timeline active={1}>
<Timeline.Item title="Order placed">
Your order has been placed.
</Timeline.Item>
<Timeline.Item title="Shipped">
Your order is on the way.
</Timeline.Item>
<Timeline.Item title="Delivered">
Package delivered.
</Timeline.Item>
</Timeline>