Component Library 43
Copy-paste HTML + CSS for every component. Requires design system tokens (see design-tokens.json).
Buttonvariant: primary|secondary|ghost|destructive, size: sm|md|lg, disabled: boolean
Preview
CSS
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; font-family: var(--font-sans); font-weight: 600; border: none; border-radius: var(--radius-md); cursor: pointer; transition: all var(--duration-fast) var(--ease-default); text-decoration: none; }
.btn--primary { background: var(--color-brand-primary); color: var(--color-text-on-brand); }
.btn--primary:hover { filter: brightness(1.1); box-shadow: var(--shadow-md); }
.btn--secondary { background: transparent; color: var(--color-text-primary); border: 1px solid var(--color-border-default); }
.btn--secondary:hover { border-color: var(--color-brand-primary); color: var(--color-brand-primary); }
.btn--ghost { background: transparent; color: var(--color-text-secondary); }
.btn--ghost:hover { background: var(--color-bg-secondary); color: var(--color-text-primary); }
.btn--destructive { background: var(--color-error); color: var(--color-text-on-error, var(--color-text-on-brand)); }
.btn--sm { height: 36px; padding: 0 16px; font-size: var(--text-body-sm); min-width: 44px; }
.btn--md { height: 44px; padding: 0 20px; font-size: var(--text-body-md); }
.btn--lg { height: 52px; padding: 0 28px; font-size: var(--text-body-lg); }
.btn:focus-visible { outline: 2px solid var(--color-brand-primary); outline-offset: 2px; }
.btn:disabled { opacity: var(--opacity-disabled); cursor: not-allowed; }HTML
<button class="btn btn--primary btn--md">Get Started</button> <button class="btn btn--secondary btn--md">Learn More</button> <button class="btn btn--ghost btn--md">Cancel</button> <button class="btn btn--destructive btn--md">Delete</button>
React
import React from 'react';
export const Button = ({ variant = 'primary', size = 'md', children, disabled = false }) => {
return (
<button className={`btn btn--${variant} btn--${size}`} disabled={disabled}>
{children}
</button>
);
};
// Usage:
// <Button variant="primary" size="md">Get Started</Button>
// <Button variant="secondary">Learn More</Button>Vue
<template>
<button :class="['uds-btn', `uds-btn--${variant}`, `uds-btn--${size}`]" :disabled="disabled">
<slot>Button</slot>
</button>
</template>
<script setup>
defineProps({
variant: { type: String, default: 'primary' },
size: { type: String, default: 'md' },
disabled: { type: Boolean, default: false }
});
</script>Svelte 5
<script lang="ts">
let { variant = 'primary', size = 'md', onclick, children, ...restProps }: {
variant?: 'primary' | 'secondary' | 'ghost' | 'destructive';
size?: 'sm' | 'md' | 'lg';
onclick?: (e: MouseEvent) => void;
children?: import('svelte').Snippet;
[key: string]: unknown;
} = $props();
</script>
<button class="uds-btn uds-btn--{variant} uds-btn--{size}" {onclick} {...restProps}>
{@render children?.()}
</button>
<style>
.uds-btn { display: inline-flex; align-items: center; justify-content: center; border-radius: var(--radius-md); font-weight: 500; transition: all var(--duration-fast) var(--ease-out); cursor: pointer; border: none; }
.uds-btn--primary { background: var(--color-brand-primary); color: var(--color-text-on-brand); }
.uds-btn--secondary { background: var(--color-bg-secondary); color: var(--color-text-primary); }
.uds-btn--ghost { background: transparent; color: var(--color-text-primary); }
.uds-btn--destructive { background: var(--color-error); color: white; }
.uds-btn--sm { height: 36px; padding: 0 12px; font-size: 0.875rem; }
.uds-btn--md { height: 44px; padding: 0 16px; }
.uds-btn--lg { height: 48px; padding: 0 24px; font-size: 1.125rem; }
</style>Inputvariant: text|email|password|number|search|textarea, size: sm|md|lg, state: default|focus|error|disabled
Preview
CSS
.input { height: 44px; width: 100%; padding: 0 12px; border: 1px solid var(--color-border-input); border-radius: var(--radius-md); font-family: var(--font-sans); font-size: 16px; color: var(--color-text-primary); background: var(--color-bg-primary); transition: border-color var(--duration-fast), box-shadow var(--duration-fast); }
.input:focus { outline: none; border-color: var(--color-brand-primary); box-shadow: 0 0 0 3px rgba(var(--color-brand-primary-rgb), 0.15); }
.input--error { border-color: var(--color-error); }
.input-label { display: block; font-size: var(--text-body-sm); font-weight: 500; margin-bottom: 4px; }
.input-helper { font-size: var(--text-body-sm); color: var(--color-text-tertiary); margin-top: 4px; }
.input-error { font-size: var(--text-body-sm); color: var(--color-error); margin-top: 4px; }HTML
<div> <label class="input-label" for="name">Full name</label> <input class="input" id="name" type="text" placeholder="Enter your name"> <div class="input-helper">As it appears on your ID</div> </div> <!-- Error state --> <div> <label class="input-label" for="email">Email</label> <input class="input input--error" id="email" type="email" value="bad" aria-invalid="true" aria-describedby="email-err"> <div class="input-error" id="email-err" role="alert">Please enter a valid email</div> </div>
React
import React, { useState } from 'react';
export const Input = ({ label, error, helper, type = 'text', placeholder = '', disabled = false }) => {
const [value, setValue] = useState('');
return (
<div>
{label && <label className="input-label">{label}</label>}
<input
className={`input ${error ? 'input--error' : ''}`}
type={type}
placeholder={placeholder}
value={value}
onChange={(e) => setValue(e.target.value)}
disabled={disabled}
/>
{error && <div className="input-error">{error}</div>}
{helper && <div className="input-helper">{helper}</div>}
</div>
);
};Vue
<template>
<div>
<label v-if="label" class="input-label">{{ label }}</label>
<input
:class="['input', { 'input--error': error }]"
:type="type"
:placeholder="placeholder"
:value="modelValue"
:disabled="disabled"
@input="$emit('update:modelValue', $event.target.value)"
/>
<div v-if="error" class="input-error">{{ error }}</div>
<div v-if="helper" class="input-helper">{{ helper }}</div>
</div>
</template>
<script setup>
defineProps({
label: String,
error: String,
helper: String,
type: { type: String, default: 'text' },
placeholder: String,
modelValue: String,
disabled: Boolean
});
defineEmits(['update:modelValue']);
</script>Svelte 5
<script lang="ts">
let { type = 'text', value = $bindable(''), placeholder = '', label = '', error = '', helper = '', disabled = false, ...restProps }: {
type?: string;
value?: string;
placeholder?: string;
label?: string;
error?: string;
helper?: string;
disabled?: boolean;
[key: string]: unknown;
} = $props();
</script>
{#if label}
<label class="input-label">{label}</label>
{/if}
<input
class={['input', error ? 'input--error' : ''].filter(Boolean).join(' ')}
{type}
bind:value
{placeholder}
{disabled}
aria-invalid={error ? 'true' : undefined}
{...restProps}
/>
{#if error}
<div class="input-error" role="alert">{error}</div>
{:else if helper}
<div class="input-helper">{helper}</div>
{/if}SelectSame sizing and states as Input
Preview
CSS
/* Uses .input class from Input component */
HTML
<label class="input-label" for="country">Country</label> <select class="input" id="country"> <option>United States</option> <option>United Kingdom</option> <option>Canada</option> </select>
Checkboxchecked: boolean, disabled: boolean
Preview
CSS
.checkbox-group { display: flex; align-items: center; gap: 8px; min-height: 44px; }
.checkbox-group input[type="checkbox"] { width: 20px; height: 20px; accent-color: var(--color-brand-primary); cursor: pointer; }
.checkbox-group label { font-size: var(--text-body-md); cursor: pointer; }HTML
<div class="checkbox-group"> <input type="checkbox" id="terms" /> <label for="terms">I agree to the terms and conditions</label> </div>
Togglechecked: boolean, disabled: boolean
Preview
CSS
.toggle { position: relative; width: 48px; height: 28px; background: var(--color-border-default); border-radius: var(--radius-full); border: none; cursor: pointer; transition: background var(--duration-fast); }
.toggle::after { content: ""; position: absolute; top: 3px; left: 3px; width: 22px; height: 22px; background: white; border-radius: var(--radius-full); transition: transform var(--duration-fast); }
.toggle.on { background: var(--color-brand-primary); }
.toggle.on::after { transform: translateX(20px); }
.toggle:focus-visible { outline: 2px solid var(--color-brand-primary); outline-offset: 2px; }HTML
<button class="toggle on" role="switch" aria-checked="true" aria-label="Enable notifications"
onclick="this.classList.toggle('on'); this.setAttribute('aria-checked', this.classList.contains('on'))">
</button>Tabsvariant: line|pill|segmented, size: sm|md, orientation: horizontal|vertical
Preview
CSS
.tabs { border-bottom: 1px solid var(--color-border-default); display: flex; }
.tab { height: 44px; padding: 0 16px; border: none; background: none; font-family: var(--font-sans); font-size: var(--text-body-sm); font-weight: 500; color: var(--color-text-secondary); cursor: pointer; border-bottom: 2px solid transparent; transition: all var(--duration-fast); }
.tab:hover { color: var(--color-text-primary); background: rgba(0,0,0,0.04); }
.tab.active { color: var(--color-text-primary); border-bottom-color: var(--color-brand-primary); font-weight: 600; }
.tab:focus-visible { outline: 2px solid var(--color-brand-primary); outline-offset: -2px; }
.tab-panel { padding: 16px 0; }HTML
<div role="tablist" class="tabs" aria-label="Settings"> <button class="tab active" role="tab" aria-selected="true" id="tab-1" aria-controls="panel-1">General</button> <button class="tab" role="tab" aria-selected="false" id="tab-2" aria-controls="panel-2">Security</button> <button class="tab" role="tab" aria-selected="false" id="tab-3" aria-controls="panel-3">Billing</button> </div> <div class="tab-panel" role="tabpanel" id="panel-1" aria-labelledby="tab-1"> General settings content... </div>
Accordiontype: single|multi, variant: bordered|flush
Preview
Answer content
CSS
.accordion { border: 1px solid var(--color-border-default); border-radius: var(--radius-lg); overflow: hidden; }
.accordion-trigger { width: 100%; display: flex; align-items: center; justify-content: space-between; height: 52px; padding: 0 16px; border: none; border-bottom: 1px solid var(--color-border-default); background: var(--color-bg-primary); font-family: var(--font-sans); font-size: var(--text-body-md); font-weight: 500; color: var(--color-text-primary); cursor: pointer; }
.accordion-trigger:hover { background: var(--color-bg-secondary); }
.accordion-trigger:focus-visible { outline: 2px solid var(--color-brand-primary); outline-offset: -2px; }
.accordion-chevron { width: 20px; height: 20px; transition: transform var(--duration-fast); }
.accordion-trigger[aria-expanded="true"] .accordion-chevron { transform: rotate(180deg); }
.accordion-content { padding: 16px; font-size: var(--text-body-sm); color: var(--color-text-secondary); }HTML
<div class="accordion">
<button class="accordion-trigger" aria-expanded="true" aria-controls="acc-1">
<span>Question text</span>
<svg class="accordion-chevron" viewBox="0 0 20 20" fill="currentColor"><path d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z"/></svg>
</button>
<div class="accordion-content" id="acc-1">Answer content...</div>
</div>Cardelevation: flat|raised|interactive
Preview
Card Title
Card description with supporting text.
CSS
.card { background: var(--color-bg-tertiary); border: 1px solid var(--color-border-default); border-radius: var(--radius-lg); padding: 24px; transition: transform var(--duration-normal) var(--ease-default), box-shadow var(--duration-normal) var(--ease-default); }
.card:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); }HTML
<div class="card"> <h3>Card Title</h3> <p>Card description with supporting text.</p> </div>
React
import React from 'react';
export const Card = ({ title, children }) => (
<div className="card">
{title && <h3>{title}</h3>}
{children}
</div>
);Vue
<template>
<div class="uds-card">
<h3 v-if="title">{{ title }}</h3>
<slot />
</div>
</template>
<script setup>
defineProps({ title: String });
</script>Svelte 5
<script lang="ts">
let { title = '', children }: {
title?: string;
children?: import('svelte').Snippet;
} = $props();
</script>
<div class="uds-card">
{#if title}<h3>{title}</h3>{/if}
{@render children?.()}
</div>Alertvariant: success|warning|error|info, dismissible: boolean
Preview
Success
Your changes have been saved.
CSS
.alert { display: flex; gap: 12px; padding: 16px; border-radius: var(--radius-md); border-left: 4px solid; }
.alert--success { border-color: var(--color-success); background: var(--color-success-bg); }
.alert--warning { border-color: var(--color-warning); background: var(--color-warning-bg); }
.alert--error { border-color: var(--color-error); background: var(--color-error-bg); }
.alert--info { border-color: var(--color-info); background: var(--color-info-bg); }
.alert-title { font-weight: 600; margin-bottom: 4px; }
.alert-body { font-size: var(--text-body-sm); color: var(--color-text-secondary); }HTML
<div class="alert alert--success" role="status">
<div>
<div class="alert-title">Success</div>
<div class="alert-body">Your changes have been saved.</div>
</div>
</div>
<div class="alert alert--error" role="alert">
<div>
<div class="alert-title">Error</div>
<div class="alert-body">Payment failed. Please try again.</div>
</div>
</div>React
import React, { useState } from 'react';
export const Alert = ({ variant = 'info', title, message, dismissible = false }) => {
const [visible, setVisible] = useState(true);
return visible && (
<div className={`alert alert--${variant}`}>
<div>
{title && <div className="alert-title">{title}</div>}
{message && <div className="alert-body">{message}</div>}
</div>
{dismissible && <button onClick={() => setVisible(false)}>✕</button>}
</div>
);
};Vue
<template>
<div v-if="visible" :class="['uds-alert', `uds-alert--${variant}`]">
<div>
<div v-if="title" class="uds-alert-title">{{ title }}</div>
<div v-if="message" class="uds-alert-body">{{ message }}</div>
</div>
<button v-if="dismissible" @click="visible = false" aria-label="Dismiss">✕</button>
</div>
</template>
<script setup>
import { ref } from 'vue';
defineProps({ variant: { type: String, default: 'info' }, title: String, message: String, dismissible: Boolean });
const visible = ref(true);
</script>Svelte 5
<script lang="ts">
let { variant = 'info', title = '', message = '', dismissible = false }: {
variant?: 'success' | 'warning' | 'error' | 'info';
title?: string;
message?: string;
dismissible?: boolean;
} = $props();
let visible = $state(true);
</script>
{#if visible}
<div class={`uds-alert uds-alert--${variant}`} role={variant === 'error' ? 'alert' : 'status'}>
<div>
{#if title}<div class="uds-alert-title">{title}</div>{/if}
{#if message}<div class="uds-alert-body">{message}</div>{/if}
</div>
{#if dismissible}
<button onclick={() => visible = false} aria-label="Dismiss">✕</button>
{/if}
</div>
{/if}Badgevariant: brand|success|warning|error|neutral, size: sm|md
Preview
NewActiveFailed
CSS
.badge { display: inline-flex; align-items: center; gap: 4px; padding: 2px 10px; border-radius: var(--radius-full); font-size: var(--text-label); font-weight: 600; }
.badge--brand { background: var(--color-brand-muted); color: var(--color-brand-primary); }
.badge--success { background: var(--color-success-bg); color: var(--color-success); }
.badge--error { background: var(--color-error-bg); color: var(--color-error); }
.badge--neutral { background: var(--color-bg-tertiary); color: var(--color-text-secondary); }HTML
<span class="badge badge--brand">New</span> <span class="badge badge--success">Active</span> <span class="badge badge--error">Failed</span> <span class="badge badge--neutral">Draft</span>
React
import React from 'react';
export const Badge = ({ variant = 'brand', children }) => (
<span className={`badge badge--${variant}`}>{children}</span>
);Vue
<template>
<span :class="['uds-badge', `uds-badge--${variant}`]"><slot /></span>
</template>
<script setup>
defineProps({ variant: { type: String, default: 'brand' } });
</script>Avatarsize: xs|sm|md|lg|xl, shape: circle|square, status: online|offline|busy|away
Preview
CSS
.avatar { display: inline-flex; align-items: center; justify-content: center; border-radius: var(--radius-full); overflow: hidden; background: var(--color-brand-muted); color: var(--color-brand-primary); font-weight: 700; flex-shrink: 0; position: relative; }
.avatar--xs { width: 24px; height: 24px; font-size: 10px; }
.avatar--sm { width: 32px; height: 32px; font-size: 12px; }
.avatar--md { width: 40px; height: 40px; font-size: 14px; }
.avatar--lg { width: 48px; height: 48px; font-size: 16px; }
.avatar--xl { width: 64px; height: 64px; font-size: 20px; }
.avatar-group { display: flex; }
.avatar-group .avatar { border: 2px solid var(--color-bg-primary); margin-left: -8px; }
.avatar-group .avatar:first-child { margin-left: 0; }
.avatar-status { position: absolute; bottom: 0; right: 0; width: 10px; height: 10px; border-radius: var(--radius-full); border: 2px solid var(--color-bg-primary); }
.avatar-status--online { background: var(--color-success); }
.avatar-status--busy { background: var(--color-error); }
.avatar-status--away { background: var(--color-warning); }HTML
<div class="avatar avatar--md">MK</div> <!-- With status --> <div class="avatar avatar--lg" style="position:relative"> JD <span class="avatar-status avatar-status--online"></span> </div> <!-- Group --> <div class="avatar-group"> <div class="avatar avatar--md">A</div> <div class="avatar avatar--md">B</div> <div class="avatar avatar--md">C</div> <div class="avatar avatar--md" style="background:var(--color-bg-tertiary);color:var(--color-text-secondary)">+5</div> </div>
Tooltipposition: top|bottom|left|right, delay: number (ms), maxWidth: number (px)
Preview
Tooltip text
CSS
.tooltip-wrap { position: relative; display: inline-block; }
.tooltip-content { position: absolute; bottom: calc(100% + 8px); left: 50%; transform: translateX(-50%); background: var(--color-bg-inverse); color: var(--color-bg-primary); padding: 6px 12px; border-radius: var(--radius-sm); font-size: var(--text-body-sm); white-space: nowrap; opacity: 0; pointer-events: none; transition: opacity var(--duration-fast); z-index: var(--z-dropdown); }
.tooltip-content::after { content: ""; position: absolute; top: 100%; left: 50%; transform: translateX(-50%); border: 6px solid transparent; border-top-color: var(--color-bg-inverse); }
.tooltip-wrap:hover .tooltip-content, .tooltip-wrap:focus-within .tooltip-content { opacity: 1; }HTML
<div class="tooltip-wrap"> <button class="btn btn--secondary btn--sm" aria-describedby="tip-1">Hover me</button> <div class="tooltip-content" id="tip-1" role="tooltip">Tooltip text here</div> </div>
Breadcrumbseparator: string (default '/')
Preview
CSS
.breadcrumb { display: flex; align-items: center; gap: 8px; font-size: var(--text-body-sm); }
.breadcrumb a { color: var(--color-text-secondary); text-decoration: none; }
.breadcrumb a:hover { color: var(--color-brand-primary); text-decoration: underline; }
.breadcrumb-sep { color: var(--color-text-tertiary); }
.breadcrumb-current { color: var(--color-text-primary); font-weight: 500; }HTML
<nav aria-label="Breadcrumb">
<div class="breadcrumb">
<a href="#">Home</a>
<span class="breadcrumb-sep" aria-hidden="true">/</span>
<a href="#">Products</a>
<span class="breadcrumb-sep" aria-hidden="true">/</span>
<span class="breadcrumb-current" aria-current="page">Detail</span>
</div>
</nav>Toastvariant: success|error|warning|info|neutral, position: top-right|bottom-right|top-center|bottom-center, duration: number (ms)
Preview
Saved
CSS
.toast-container { position: fixed; bottom: 16px; right: 16px; z-index: var(--z-toast); display: flex; flex-direction: column; gap: 8px; }
.toast { display: flex; align-items: flex-start; gap: 12px; min-width: 320px; max-width: 420px; padding: 12px 16px; background: var(--color-bg-primary); border: 1px solid var(--color-border-default); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); border-left: 4px solid; }
.toast--success { border-left-color: var(--color-success); }
.toast--error { border-left-color: var(--color-error); }
.toast--warning { border-left-color: var(--color-warning); }
.toast--info { border-left-color: var(--color-info); }
.toast-title { font-weight: 600; font-size: var(--text-body-sm); }
.toast-message { font-size: var(--text-body-sm); color: var(--color-text-secondary); margin-top: 2px; }HTML
<div class="toast-container">
<div class="toast toast--success" role="status">
<div>
<div class="toast-title">Saved</div>
<div class="toast-message">Changes saved successfully.</div>
</div>
</div>
</div>Paginationvariant: numbered|simple|load-more|infinite
Preview
CSS
.pagination { display: flex; align-items: center; gap: 4px; }
.page-btn { width: 36px; height: 36px; display: inline-flex; align-items: center; justify-content: center; border: 1px solid var(--color-border-default); border-radius: var(--radius-md); background: var(--color-bg-primary); font-size: var(--text-body-sm); cursor: pointer; transition: all var(--duration-fast); }
.page-btn:hover { background: var(--color-bg-secondary); }
.page-btn.active { background: var(--color-brand-primary); color: var(--color-text-on-brand); border-color: var(--color-brand-primary); }
.page-btn:disabled { opacity: var(--opacity-disabled); cursor: not-allowed; }
.page-ellipsis { width: 36px; text-align: center; color: var(--color-text-tertiary); }HTML
<nav aria-label="Pagination">
<div class="pagination">
<button class="page-btn" disabled aria-label="Previous">«</button>
<button class="page-btn active" aria-current="page" aria-label="Page 1">1</button>
<button class="page-btn" aria-label="Page 2">2</button>
<button class="page-btn" aria-label="Page 3">3</button>
<span class="page-ellipsis">...</span>
<button class="page-btn" aria-label="Page 12">12</button>
<button class="page-btn" aria-label="Next">»</button>
</div>
</nav>Skeletonvariant: text|circle|rectangle|custom
Preview
CSS
.skeleton { background: linear-gradient(90deg, var(--color-bg-tertiary) 25%, var(--color-bg-secondary) 50%, var(--color-bg-tertiary) 75%); background-size: 200% 100%; animation: shimmer 1.5s infinite; border-radius: 4px; }
.skeleton-line { height: 16px; margin-bottom: 12px; }
.skeleton-circle { border-radius: var(--radius-full); }
@keyframes shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) { .skeleton { animation: none; } }HTML
<div aria-busy="true">
<div style="display:flex;gap:16px;align-items:flex-start">
<div class="skeleton skeleton-circle" style="width:48px;height:48px;flex-shrink:0" aria-hidden="true"></div>
<div style="flex:1">
<div class="skeleton skeleton-line" style="width:40%" aria-hidden="true"></div>
<div class="skeleton skeleton-line" style="width:100%" aria-hidden="true"></div>
<div class="skeleton skeleton-line" style="width:80%" aria-hidden="true"></div>
</div>
</div>
</div>DataTablesortable: boolean, selectable: boolean, striped: boolean, stickyHeader: boolean, density: compact|default|comfortable
Preview
| Name | Status | Role |
|---|---|---|
| Alice | Active | Admin |
CSS
.data-table { width: 100%; border-collapse: collapse; border: 1px solid var(--color-border-default); border-radius: var(--radius-lg); overflow: hidden; }
.data-table th { padding: 0 16px; height: 44px; background: var(--color-bg-secondary); font-weight: 600; font-size: var(--text-body-sm); text-align: left; border-bottom: 2px solid var(--color-border-default); }
.data-table td { padding: 0 16px; height: 48px; border-bottom: 1px solid var(--color-border-subtle); font-size: var(--text-body-sm); }
.data-table tr:hover td { background: var(--color-bg-secondary); }
.data-table--striped tr:nth-child(odd) td { background: var(--color-bg-secondary); }HTML
<table class="data-table">
<thead>
<tr><th>Name</th><th>Status</th><th>Role</th></tr>
</thead>
<tbody>
<tr><td>Alice Johnson</td><td><span class="badge badge--success">Active</span></td><td>Admin</td></tr>
<tr><td>Bob Smith</td><td><span class="badge badge--brand">Pending</span></td><td>Editor</td></tr>
</tbody>
</table>Modalopen: boolean, onClose: function
CSS
.modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.5); backdrop-filter: blur(4px); display: flex; align-items: center; justify-content: center; z-index: var(--z-modal); }
.modal { max-width: 560px; width: 90%; padding: 32px; background: var(--color-bg-primary); border-radius: var(--radius-xl); box-shadow: var(--shadow-xl); animation: modal-in var(--duration-normal) var(--ease-out); }
.modal-title { font-size: var(--text-heading-md); font-weight: 600; margin-bottom: 8px; }
.modal-body { color: var(--color-text-secondary); margin-bottom: 24px; }
.modal-actions { display: flex; gap: 8px; justify-content: flex-end; }
@keyframes modal-in { from { opacity: 0; transform: scale(0.95); } to { opacity: 1; transform: scale(1); } }HTML
<div class="modal-overlay" role="dialog" aria-modal="true" aria-labelledby="modal-title">
<div class="modal">
<h2 class="modal-title" id="modal-title">Confirm action</h2>
<p class="modal-body">Are you sure you want to proceed?</p>
<div class="modal-actions">
<button class="btn btn--secondary btn--md">Cancel</button>
<button class="btn btn--primary btn--md">Confirm</button>
</div>
</div>
</div>CodeBlocklanguage: string, showLineNumbers: boolean
CSS
.code-block { background: #1E1E2E; color: #D4D4E8; border-radius: var(--radius-lg); overflow: hidden; }
.code-block-header { display: flex; align-items: center; justify-content: space-between; padding: var(--space-2) var(--space-4); background: var(--color-code-header-bg); font-size: var(--text-label); }
.code-block-lang { color: var(--color-code-muted); }
.code-block-copy { padding: var(--space-1) var(--space-3); font-size: 11px; background: rgba(255,255,255,0.1); color: var(--color-code-muted); border: none; border-radius: var(--radius-sm); cursor: pointer; }
.code-block pre { padding: 20px; font-family: var(--font-mono); font-size: 13px; line-height: 1.6; overflow-x: auto; margin: 0; }HTML
<div class="code-block">
<div class="code-block-header">
<span class="code-block-lang">javascript</span>
<button class="code-block-copy">Copy</button>
</div>
<pre><code>const greeting = 'Hello, World!';</code></pre>
</div>PricingTablecolumns: 2|3|4, featured: index, toggle: boolean (monthly/annual)
CSS
.pricing-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; max-width: 1120px; }
.pricing-card { padding: 40px; border: 1px solid var(--color-border-default); border-radius: var(--radius-lg); background: var(--color-bg-primary); }
.pricing-card--featured { border: 2px solid var(--color-brand-primary); box-shadow: var(--shadow-lg); position: relative; }
.pricing-name { font-size: var(--text-heading-sm); font-weight: 600; }
.pricing-price { font-size: var(--text-display-md); font-weight: 800; margin: 16px 0; }
.pricing-price span { font-size: var(--text-body-sm); font-weight: 400; color: var(--color-text-secondary); }
.pricing-features { list-style: none; margin: 24px 0; }
.pricing-features li { padding: 8px 0; font-size: var(--text-body-sm); color: var(--color-text-secondary); }HTML
<div class="pricing-grid">
<div class="pricing-card">
<div class="pricing-name">Starter</div>
<div class="pricing-price">$9<span>/mo</span></div>
<ul class="pricing-features"><li>✓ 5 projects</li><li>✓ Basic analytics</li></ul>
<button class="btn btn--secondary btn--md" style="width:100%">Get Started</button>
</div>
<div class="pricing-card pricing-card--featured">
<div class="pricing-name">Pro</div>
<div class="pricing-price">$29<span>/mo</span></div>
<ul class="pricing-features"><li>✓ Unlimited projects</li><li>✓ Advanced analytics</li></ul>
<button class="btn btn--primary btn--md" style="width:100%">Get Started</button>
</div>
</div>Radiochecked: boolean, disabled: boolean, variant: standard|card
CSS
.radio-group { display: flex; flex-direction: column; gap: 4px; }
.radio-label { display: flex; align-items: center; gap: 8px; min-height: 44px; cursor: pointer; font-size: var(--text-body-md); }
.radio-label input[type="radio"] { width: 20px; height: 20px; accent-color: var(--color-brand-primary); cursor: pointer; flex-shrink: 0; }
.radio-label input:disabled { opacity: var(--opacity-disabled); cursor: not-allowed; }
.radio-label input:focus-visible { outline: 2px solid var(--color-brand-primary); outline-offset: 2px; }HTML
<fieldset>
<legend class="input-label">Billing frequency</legend>
<div class="radio-group">
<label class="radio-label">
<input type="radio" name="billing" value="monthly" checked /> Monthly
</label>
<label class="radio-label">
<input type="radio" name="billing" value="annual" /> Annual (save 20%)
</label>
</div>
</fieldset>Hero Sectionvariant: centered|split|gradient-mesh|video-bg, size: full(85vh)|compact(60vh)
CSS
.hero { text-align: center; padding: 80px 24px; min-height: 85vh; display: flex; flex-direction: column; align-items: center; justify-content: center; }
.hero-headline { font-family: var(--font-display); font-size: var(--text-display-xl); font-weight: 800; letter-spacing: -0.02em; max-width: 800px; margin-bottom: 16px; }
.hero-subheadline { font-size: var(--text-body-lg); color: var(--color-text-secondary); max-width: 600px; margin-bottom: 32px; }
.hero-actions { display: flex; gap: 12px; flex-wrap: wrap; justify-content: center; }
.hero--gradient { background: var(--gradient-hero); color: var(--color-text-on-brand); }
.hero--gradient .hero-subheadline { color: rgba(255,255,255,0.85); }
.hero--dark { background: var(--color-bg-inverse); color: var(--color-bg-primary); }
.hero--dark .hero-subheadline { color: rgba(255,255,255,0.7); }HTML
<section class="hero">
<h1 class="hero-headline">Build faster, ship smarter</h1>
<p class="hero-subheadline">The platform teams love for building products that delight customers.</p>
<div class="hero-actions">
<button class="btn btn--lg btn--primary">Start Free Trial</button>
<button class="btn btn--lg btn--secondary">Watch Demo</button>
</div>
</section>Testimonial Cardvariant: quote-card|video|metric|carousel
“This design system transformed our workflow completely.”
Sarah Kim
VP Engineering, TechCorp
CSS
.testimonial { padding: 32px; background: var(--color-bg-tertiary); border: 1px solid var(--color-border-default); border-radius: var(--radius-lg); }
.testimonial blockquote { font-size: var(--text-body-lg); font-style: italic; line-height: 1.7; margin-bottom: 24px; }
.testimonial-author { display: flex; align-items: center; gap: 12px; }
.testimonial-avatar { width: 48px; height: 48px; border-radius: var(--radius-full); background: var(--color-brand-muted); display: flex; align-items: center; justify-content: center; font-weight: 700; color: var(--color-brand-primary); }
.testimonial-name { font-weight: 600; }
.testimonial-role { font-size: var(--text-body-sm); color: var(--color-text-secondary); }HTML
<div class="testimonial">
<blockquote>“This platform transformed our workflow.”</blockquote>
<div class="testimonial-author">
<div class="testimonial-avatar">SK</div>
<div>
<div class="testimonial-name">Sarah Kim</div>
<div class="testimonial-role">VP Engineering, TechCorp</div>
</div>
</div>
</div>Progress Indicatorvariant: bar|circular|stepper, value: number, max: number, indeterminate: boolean
Uploading... 65%
Processing...
CSS
.progress { height: 8px; background: var(--color-bg-tertiary); border-radius: var(--radius-full); overflow: hidden; }
.progress-bar { height: 100%; background: var(--color-brand-primary); border-radius: var(--radius-full); transition: width var(--duration-normal) var(--ease-default); }
.progress-label { font-size: var(--text-body-sm); font-weight: 500; margin-bottom: 4px; }
/* Indeterminate */
.progress--indeterminate .progress-bar { width: 100%; background: linear-gradient(90deg, var(--color-brand-primary) 0%, var(--color-brand-muted) 50%, var(--color-brand-primary) 100%); background-size: 200% 100%; animation: progress-shimmer 1.5s linear infinite; }
@keyframes progress-shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) { .progress--indeterminate .progress-bar { animation: none; } }HTML
<div>
<div class="progress-label">Uploading... 65%</div>
<div class="progress" role="progressbar" aria-valuenow="65" aria-valuemin="0" aria-valuemax="100">
<div class="progress-bar" style="width: 65%"></div>
</div>
</div>
<!-- Indeterminate -->
<div class="progress progress--indeterminate" role="progressbar" aria-label="Loading">
<div class="progress-bar"></div>
</div>Date Pickervariant: single|range|with-time, min: date, max: date, locale: string
CSS
.date-input { width: 100%; max-width: 280px; height: 44px; padding: 0 12px; font-family: var(--font-sans); font-size: var(--text-body-md); color: var(--color-text-primary); background: var(--color-bg-primary); border: 1px solid var(--color-border-input); border-radius: var(--radius-md); transition: border-color var(--duration-fast), box-shadow var(--duration-fast); }
.date-input:focus { outline: none; border-color: var(--color-brand-primary); box-shadow: 0 0 0 3px rgba(var(--color-brand-primary-rgb), 0.15); }
.date-calendar { background: var(--color-bg-primary); border: 1px solid var(--color-border-default); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); padding: 16px; width: 300px; }
.date-calendar-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; font-weight: 600; }
.date-calendar-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; text-align: center; }
.date-cell { width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; border-radius: var(--radius-full); font-size: var(--text-body-sm); cursor: pointer; }
.date-cell:hover { background: var(--color-bg-secondary); }
.date-cell--selected { background: var(--color-brand-primary); color: var(--color-text-on-brand); }
.date-cell--today { font-weight: 700; color: var(--color-brand-primary); }
.date-cell--disabled { opacity: var(--opacity-disabled); cursor: not-allowed; }HTML
<label class="input-label" for="date">Select date</label>
<input type="date" class="date-input" id="date" />
<!-- Custom calendar panel (JS required for full implementation) -->
<div class="date-calendar" role="grid" aria-label="March 2026">
<div class="date-calendar-header">
<button aria-label="Previous month">‹</button>
<span>March 2026</span>
<button aria-label="Next month">›</button>
</div>
<div class="date-calendar-grid" role="row">
<div class="date-cell date-cell--today" role="gridcell" aria-selected="false">11</div>
<div class="date-cell date-cell--selected" role="gridcell" aria-selected="true">15</div>
</div>
</div>Command Paletteactions: Action[], groups: Group[], placeholder: string
CSS
.command-palette-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.5); backdrop-filter: blur(4px); display: flex; align-items: flex-start; justify-content: center; padding-top: 20vh; z-index: var(--z-modal); }
.command-palette { width: 560px; max-height: 400px; background: var(--color-bg-primary); border: 1px solid var(--color-border-default); border-radius: var(--radius-xl); box-shadow: var(--shadow-xl); overflow: hidden; }
.command-input { width: 100%; height: 52px; padding: 0 20px; border: none; border-bottom: 1px solid var(--color-border-default); font-family: var(--font-sans); font-size: var(--text-body-md); background: transparent; color: var(--color-text-primary); outline: none; }
.command-input::placeholder { color: var(--color-text-tertiary); }
.command-list { overflow-y: auto; max-height: 320px; padding: 8px; }
.command-group-label { padding: 8px 12px; font-size: var(--text-label); font-weight: 600; color: var(--color-text-tertiary); text-transform: uppercase; letter-spacing: 0.05em; }
.command-item { display: flex; align-items: center; gap: 12px; padding: 0 12px; height: 40px; border-radius: var(--radius-md); cursor: pointer; font-size: var(--text-body-sm); }
.command-item:hover, .command-item--active { background: var(--color-bg-secondary); }
.command-shortcut { margin-left: auto; font-size: var(--text-label); color: var(--color-text-tertiary); font-family: var(--font-mono); }HTML
<div class="command-palette-overlay">
<div class="command-palette" role="combobox" aria-expanded="true" aria-haspopup="listbox">
<input class="command-input" type="text" placeholder="Type a command or search..." aria-label="Command palette" />
<div class="command-list" role="listbox">
<div class="command-group-label">Actions</div>
<div class="command-item command-item--active" role="option" aria-selected="true">
New project <span class="command-shortcut">⌘N</span>
</div>
<div class="command-item" role="option">
Search files <span class="command-shortcut">⌘P</span>
</div>
<div class="command-group-label">Navigation</div>
<div class="command-item" role="option">Go to Dashboard</div>
<div class="command-item" role="option">Go to Settings</div>
</div>
</div>
</div>Feature Cardvariant: icon-top|image-top|horizontal|stat-card, title, description, link
Preview
Feature title
Supporting description for the feature.
CSS
.feature-card { padding: 24px; border: 1px solid var(--color-border-default); border-radius: var(--radius-lg); background: var(--color-bg-primary); }
.feature-card__icon { width: 48px; height: 48px; border-radius: var(--radius-md); background: var(--color-brand-muted); margin-bottom: 16px; }
.feature-card__title { font-size: var(--text-heading-sm); margin-bottom: 8px; }
.feature-card__desc { font-size: var(--text-body-sm); color: var(--color-text-secondary); }HTML
<div class="feature-card"> <div class="feature-card__icon" aria-hidden="true"></div> <h3 class="feature-card__title">Feature title</h3> <p class="feature-card__desc">Supporting description.</p> </div>
File Uploadvariant: dropzone|button|avatar-upload, accept, maxSize, multiple
Preview
Drag and drop files or click to upload
CSS
.file-dropzone { border: 2px dashed var(--color-border-default); border-radius: var(--radius-lg); padding: 32px; text-align: center; background: var(--color-bg-tertiary); cursor: pointer; transition: border-color var(--duration-fast); }
.file-dropzone:hover { border-color: var(--color-brand-primary); }
.file-dropzone input[type="file"] { position: absolute; opacity: 0; width: 100%; height: 100%; cursor: pointer; }HTML
<label class="file-dropzone"> <input type="file" multiple aria-label="Upload files" /> Drag and drop or click to upload </label>
Drawerside: left|right|top|bottom, open: boolean, onClose
CSS
.drawer-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.4); z-index: var(--z-modal); }
.drawer { position: fixed; top: 0; right: 0; width: 400px; max-width: 100%; height: 100vh; background: var(--color-bg-primary); box-shadow: var(--shadow-xl); z-index: var(--z-modal); padding: 24px; overflow-y: auto; }
.drawer-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px; }HTML
<div class="drawer-overlay" aria-hidden="true">
<div class="drawer" role="dialog" aria-modal="true" aria-label="Panel">
<div class="drawer-header"><h2>Title</h2><button aria-label="Close">×</button></div>
<p>Drawer content.</p>
</div>
</div>Popoverposition: top|bottom|left|right|auto, content, trigger
Preview
Popover content
CSS
.popover { position: absolute; padding: 12px; background: var(--color-bg-primary); border: 1px solid var(--color-border-default); border-radius: var(--radius-md); box-shadow: var(--shadow-lg); z-index: var(--z-dropdown); font-size: var(--text-body-sm); }HTML
<div style="position:relative"> <button id="popover-trigger" aria-haspopup="true" aria-expanded="false">Trigger</button> <div class="popover" role="dialog" id="popover-content" hidden>Content</div> </div>
Comboboxvariant: autocomplete|multiselect|creatable, options[], placeholder, onSelect
Preview
Option 1
Option 2
Option 3
Option 2
Option 3
CSS
.combobox-listbox { margin-top: 4px; padding: 8px; background: var(--color-bg-primary); border: 1px solid var(--color-border-default); border-radius: var(--radius-md); max-height: 240px; overflow-y: auto; }
.combobox-option { padding: 8px 12px; border-radius: var(--radius-sm); cursor: pointer; }
.combobox-option[aria-selected="true"] { background: var(--color-brand-muted); }HTML
<div role="combobox" aria-expanded="false" aria-haspopup="listbox"> <input type="text" aria-autocomplete="list" aria-controls="listbox" aria-activedescendant="" /> <ul id="listbox" role="listbox" class="combobox-listbox" hidden><li role="option">Option 1</li></ul> </div>
Alert Dialogvariant: info|warning|destructive, title, description, onConfirm, onCancel
CSS
.alert-dialog-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center; z-index: var(--z-modal); }
.alert-dialog { max-width: 400px; padding: 24px; background: var(--color-bg-primary); border-radius: var(--radius-lg); box-shadow: var(--shadow-xl); }
.alert-dialog__actions { display: flex; gap: 12px; justify-content: flex-end; margin-top: 24px; }HTML
<div class="alert-dialog-overlay" role="alertdialog" aria-modal="true" aria-labelledby="alert-title" aria-describedby="alert-desc">
<div class="alert-dialog">
<h2 id="alert-title">Confirm action</h2>
<p id="alert-desc">This action cannot be undone.</p>
<div class="alert-dialog__actions"><button class="btn btn--secondary">Cancel</button><button class="btn btn--primary">Confirm</button></div>
</div>
</div>Carouselvariant: slide|fade|auto-play, items[], showDots, showArrows
Preview
CSS
.carousel { position: relative; overflow: hidden; border-radius: var(--radius-lg); }
.carousel-track { display: flex; transition: transform var(--duration-normal) var(--ease-default); }
.carousel-slide { flex: 0 0 100%; min-width: 0; }
.carousel-dots { display: flex; gap: 8px; justify-content: center; margin-top: 16px; }
.carousel-dot { width: 8px; height: 8px; border-radius: 9999px; background: var(--color-border-default); cursor: pointer; }
.carousel-dot--active { background: var(--color-brand-primary); }HTML
<section class="carousel" role="region" aria-roledescription="carousel" aria-label="Content carousel"> <div class="carousel-track"><div class="carousel-slide">Slide 1</div><div class="carousel-slide">Slide 2</div></div> <div class="carousel-dots" role="tablist"><button role="tab" aria-selected="true" class="carousel-dot carousel-dot--active"></button><button role="tab" class="carousel-dot"></button></div> </section>
Chip Inputchips[], onAdd, onRemove, maxChips, placeholder
Preview
Tag 1Tag 2
CSS
.chip-input { display: flex; flex-wrap: wrap; gap: 8px; padding: 8px 12px; border: 1px solid var(--color-border-input); border-radius: var(--radius-md); min-height: 44px; background: var(--color-bg-primary); }
.chip { padding: 4px 8px; background: var(--color-brand-muted); border-radius: var(--radius-sm); font-size: var(--text-body-sm); display: inline-flex; align-items: center; gap: 4px; }
.chip-remove { background: none; border: none; cursor: pointer; padding: 0 2px; }
.chip-input input { border: none; flex: 1; min-width: 80px; background: transparent; outline: none; font-size: var(--text-body-md); }HTML
<div class="chip-input" role="listbox"> <span class="chip" role="option">Tag 1 <button class="chip-remove" aria-label="Remove">×</button></span> <input type="text" aria-label="Add chip" placeholder="Add..." /> </div>
Steppersteps[], activeStep, orientation: horizontal|vertical, linear: boolean
Preview
123
CSS
.stepper { display: flex; align-items: center; gap: 8px; }
.stepper-step { width: 28px; height: 28px; border-radius: 9999px; display: flex; align-items: center; justify-content: center; font-size: var(--text-body-sm); font-weight: 600; }
.stepper-step--active, .stepper-step--completed { background: var(--color-brand-primary); color: var(--color-text-on-brand); }
.stepper-step--pending { border: 2px solid var(--color-border-default); color: var(--color-text-tertiary); }
.stepper-connector { width: 40px; height: 2px; background: var(--color-border-subtle); }
.stepper-connector--completed { background: var(--color-brand-primary); }HTML
<nav class="stepper" aria-label="Progress"> <span class="stepper-step stepper-step--completed" aria-current="step">1</span> <span class="stepper-connector stepper-connector--completed"></span> <span class="stepper-step stepper-step--active">2</span> <span class="stepper-connector"></span> <span class="stepper-step stepper-step--pending">3</span> </nav>
Segmented Controloptions[], value, onChange, variant: default|icon-only
Preview
CSS
.segmented-control { display: inline-flex; padding: 4px; background: var(--color-bg-tertiary); border-radius: var(--radius-md); gap: 2px; }
.segmented-control [role="radio"] { border-radius: 6px; }
.segmented-control [role="radio"][aria-checked="true"] { background: var(--color-bg-primary); box-shadow: var(--shadow-xs); }HTML
<div class="segmented-control" role="radiogroup" aria-label="Options"> <button role="radio" aria-checked="true">Option A</button> <button role="radio" aria-checked="false">Option B</button> <button role="radio" aria-checked="false">Option C</button> </div>
Toolbarorientation: horizontal|vertical, items[], ariaLabel
Preview
CSS
.toolbar { display: flex; gap: 4px; padding: 8px; background: var(--color-bg-tertiary); border-radius: var(--radius-md); }
.toolbar-divider { width: 1px; background: var(--color-border-default); align-self: stretch; }HTML
<div class="toolbar" role="toolbar" aria-label="Formatting"> <button type="button" aria-label="Bold">B</button> <button type="button" aria-label="Italic">I</button> <span class="toolbar-divider" aria-hidden="true"></span> <button type="button" aria-label="List">List</button> </div>
Tree Viewdata[], selectionMode: single|multi|checkbox, onSelect, onExpand
Preview
Documents
File 1
File 2
CSS
.tree { font-size: var(--text-body-sm); }
.tree-item { display: flex; align-items: center; gap: 8px; padding: 8px 12px; cursor: pointer; border-radius: var(--radius-sm); }
.tree-item:hover { background: var(--color-bg-secondary); }
.tree-item[aria-expanded="true"] { font-weight: 600; }
.tree-group { padding-left: 20px; }
.tree-leaf { padding: 6px 12px; border-radius: var(--radius-sm); }HTML
<div class="tree" role="tree" aria-label="Folder structure"> <div class="tree-item" role="treeitem" aria-expanded="true"><span>▼</span><span>Documents</span></div> <div class="tree-group" role="group"><div class="tree-leaf" role="treeitem">File 1</div><div class="tree-leaf" role="treeitem">File 2</div></div> </div>
OTP Inputlength: 4|6, value, onChange, inputMode: numeric|alphanumeric
Preview
CSS
.otp-input { display: flex; gap: 8px; }
.otp-input input { width: 48px; height: 52px; text-align: center; font-size: 1.5rem; border: 1px solid var(--color-border-input); border-radius: var(--radius-md); font-family: var(--font-mono); }
.otp-input input:focus { outline: none; border-color: var(--color-brand-primary); box-shadow: 0 0 0 3px rgba(var(--color-brand-primary-rgb), 0.15); }HTML
<div class="otp-input" role="group" aria-label="One-time code"> <input type="text" inputmode="numeric" maxlength="1" aria-label="Digit 1" autocomplete="one-time-code" /> <input type="text" inputmode="numeric" maxlength="1" aria-label="Digit 2" /> <input type="text" inputmode="numeric" maxlength="1" aria-label="Digit 3" /> <input type="text" inputmode="numeric" maxlength="1" aria-label="Digit 4" /> </div>
.social-proof { text-align: center; padding: 40px 24px; } .social-proof-label { font-size: var(--text-label); text-transform: uppercase; letter-spacing: 0.08em; font-weight: 600; color: var(--color-text-tertiary); margin-bottom: 24px; } .logo-bar { display: flex; align-items: center; justify-content: center; gap: 48px; flex-wrap: wrap; } .logo-bar img { height: 32px; opacity: 0.6; filter: grayscale(100%); transition: all var(--duration-normal); } .logo-bar img:hover { opacity: 1; filter: grayscale(0%); }<section class="social-proof"> <p class="social-proof-label">Trusted by industry leaders</p> <div class="logo-bar" role="list" aria-label="Trusted companies"> <img src="logo-google.svg" alt="Google" role="listitem" /> <img src="logo-stripe.svg" alt="Stripe" role="listitem" /> <img src="logo-shopify.svg" alt="Shopify" role="listitem" /> <img src="logo-notion.svg" alt="Notion" role="listitem" /> </div> </section>