React Components¶
Pre-built React components that encapsulate the design system styles.
Installation¶
Import components from the package:
import {
NeuCard,
NeuButton,
NeuInput,
NeuSelect,
NeuCheckbox,
NeuRadio,
NeuToggle,
NeuTabNav,
NeuAlert,
Button,
Pill,
StatusPill,
StatusDot,
IconActionButton,
InfraCard,
DetailScreenHeader,
GraphViewLayout,
ThemeLifecyclePill,
ThemeVersionPill,
} from '@bast/shared-styles/components';
NeuCard¶
Neumorphic card component with multiple variants.
Props¶
| Prop | Type | Default | Description |
|---|---|---|---|
variant |
'raised' \| 'inset' \| 'flat' \| 'glow' |
'raised' |
Visual variant |
interactive |
boolean |
false |
Enable hover effect |
radius |
'small' \| 'default' \| 'large' |
'default' |
Border radius |
className |
string |
'' |
Additional classes |
children |
ReactNode |
- | Card content |
Examples¶
// Basic raised card
<NeuCard className="p-4">
<h3>Card Title</h3>
<p>Card content</p>
</NeuCard>
// Interactive card
<NeuCard variant="raised" interactive className="p-4">
<h3>Click me</h3>
</NeuCard>
// Inset card
<NeuCard variant="inset" className="p-4">
<p>Recessed content</p>
</NeuCard>
// AI glow effect
<NeuCard variant="glow" className="p-4">
<p>AI-powered feature</p>
</NeuCard>
GraphViewLayout¶
Shared two-panel graph shell used by admin graph screens.
Props¶
| Prop | Type | Default | Description |
|---|---|---|---|
treePanel |
ReactNode |
- | Left graph tree content (required) |
detailPanel |
ReactNode |
- | Right detail panel content (required) |
minHeightClass |
string |
'min-h-[400px]' |
Left panel minimum height utility class |
detailWidthClass |
string |
'w-80' |
Right panel width utility class |
detailPanelRole |
AriaRole |
- | Optional semantic role for detail panel |
detailPanelAriaLabel |
string |
- | Optional aria-label for detail panel |
Example¶
import { GraphViewLayout } from '@bast/shared-styles/components';
<GraphViewLayout
minHeightClass="min-h-[400px]"
detailWidthClass="w-[380px]"
detailPanelRole="complementary"
detailPanelAriaLabel="Graph node details"
treePanel={<div>Tree content</div>}
detailPanel={<div>Detail content</div>}
/>
NeuButton¶
Button component with built-in variants and states.
Props¶
| Prop | Type | Default | Description |
|---|---|---|---|
variant |
'primary' \| 'success' \| 'warning' \| 'error' |
'primary' |
Color variant |
size |
'small' \| 'default' \| 'large' |
'default' |
Button size |
fullWidth |
boolean |
false |
Full width button |
icon |
ReactNode |
- | Icon before label |
disabled |
boolean |
false |
Disabled state |
Examples¶
// Basic button
<NeuButton>Click me</NeuButton>
// Success button with icon
<NeuButton variant="success" icon={<CheckIcon />}>
Save Changes
</NeuButton>
// Large error button
<NeuButton variant="error" size="large" fullWidth>
Delete Account
</NeuButton>
// Disabled button
<NeuButton disabled>Disabled</NeuButton>
Action Button Groups (Design System Rule)¶
When rendering a group of action buttons (Save/Cancel, Confirm/Dismiss, etc.), follow these rules:
- Right-align the button group to its container (
justify-end) - Pin to bottom of the container/card (
mt-auto, with aborder-tseparator) - Primary action rightmost — Save, Confirm, Submit go on the far right
- Secondary/cancel action left — Cancel, Dismiss go to the left of the primary action
This applies universally to all edit panels, modals, forms, and dialogs.
// Correct — Cancel left, Save right, right-aligned, pinned to bottom
<div className="mt-auto flex items-center justify-end gap-2 border-t border-[var(--border)] pt-4">
<NeuButton size="sm" variant="secondary" onClick={onCancel}>Cancel</NeuButton>
<NeuButton size="sm" variant="primary" onClick={onSave}>Save</NeuButton>
</div>
// Also correct for destructive actions — Cancel left, Delete right
<div className="mt-auto flex items-center justify-end gap-2 border-t border-[var(--border)] pt-4">
<NeuButton variant="secondary" onClick={onCancel}>Cancel</NeuButton>
<NeuButton variant="error" onClick={onDelete}>Delete</NeuButton>
</div>
NeuInput¶
Text input with label, helper text, and error states.
Props¶
| Prop | Type | Default | Description |
|---|---|---|---|
label |
string |
- | Input label |
helperText |
string |
- | Helper text below input |
error |
string |
- | Error message (triggers error state) |
size |
'small' \| 'default' \| 'large' |
'default' |
Input size |
wrapperClassName |
string |
'' |
Wrapper element classes |
Examples¶
// Basic input
<NeuInput placeholder="Enter text..." />
// Input with label and helper
<NeuInput
label="Email"
placeholder="you@example.com"
helperText="We'll never share your email"
/>
// Error state
<NeuInput
label="Password"
type="password"
error="Password must be at least 8 characters"
/>
// Controlled input
const [value, setValue] = useState('');
<NeuInput
value={value}
onChange={(e) => setValue(e.target.value)}
/>
NeuSelect¶
Raised dropdown select component with a styled popup menu.
Props¶
| Prop | Type | Default | Description |
|---|---|---|---|
label |
string |
- | Select label |
helperText |
string |
- | Helper text |
error |
string |
- | Error message |
size |
'small' \| 'default' \| 'large' |
'default' |
Select size |
onValueChange |
(value: string) => void |
- | Direct value change callback |
children |
ReactNode |
- | Option elements |
Examples¶
// Basic select
<NeuSelect>
<option>Select an option</option>
<option value="1">Option 1</option>
<option value="2">Option 2</option>
</NeuSelect>
// With label
<NeuSelect label="Country">
<option value="">Select country</option>
<option value="us">United States</option>
<option value="ca">Canada</option>
</NeuSelect>
// Error state
<NeuSelect
label="Priority"
error="Please select a priority level"
onValueChange={(value) => console.log(value)}
>
<option value="">Select priority</option>
<option value="low">Low</option>
<option value="high">High</option>
</NeuSelect>
NeuCheckbox¶
Styled checkbox component.
Props¶
| Prop | Type | Default | Description |
|---|---|---|---|
label |
string |
- | Checkbox label |
disabled |
boolean |
false |
Disabled state |
wrapperClassName |
string |
'' |
Wrapper classes |
Examples¶
// Basic checkbox
<NeuCheckbox label="Accept terms and conditions" />
// Default checked
<NeuCheckbox label="Remember me" defaultChecked />
// Disabled
<NeuCheckbox label="Unavailable option" disabled />
// Controlled
const [checked, setChecked] = useState(false);
<NeuCheckbox
label="Enable feature"
checked={checked}
onChange={(e) => setChecked(e.target.checked)}
/>
NeuToggle¶
Toggle/switch component.
Props¶
| Prop | Type | Default | Description |
|---|---|---|---|
label |
string |
- | Toggle label |
labelPosition |
'left' \| 'right' |
'right' |
Label position |
disabled |
boolean |
false |
Disabled state |
Examples¶
// Basic toggle
<NeuToggle label="Enable notifications" />
// Label on left
<NeuToggle label="Dark mode" labelPosition="left" />
// Controlled
const [enabled, setEnabled] = useState(false);
<NeuToggle
label="Feature flag"
checked={enabled}
onChange={(e) => setEnabled(e.target.checked)}
/>
NeuAlert¶
Alert/notification component.
Props¶
| Prop | Type | Default | Description |
|---|---|---|---|
variant |
'success' \| 'info' \| 'warning' \| 'error' |
- | Alert type (required) |
title |
string |
- | Alert title (required) |
message |
string |
- | Alert message |
icon |
ReactNode |
- | Custom icon |
dismissible |
boolean |
false |
Show close button |
onDismiss |
() => void |
- | Close callback |
Examples¶
// Success alert
<NeuAlert
variant="success"
title="Success!"
message="Your changes have been saved."
/>
// Error alert
<NeuAlert
variant="error"
title="Error"
message="Something went wrong. Please try again."
/>
// Dismissible alert
const [show, setShow] = useState(true);
{show && (
<NeuAlert
variant="info"
title="Notice"
message="This is an important message."
dismissible
onDismiss={() => setShow(false)}
/>
)}
// Custom icon
<NeuAlert
variant="warning"
title="Heads up"
message="This action cannot be undone."
icon={<CustomWarningIcon />}
/>
TypeScript Support¶
All components export their prop types:
import type {
NeuCardProps,
NeuButtonProps,
NeuInputProps,
NeuSelectProps,
NeuCheckboxProps,
NeuToggleProps,
NeuAlertProps,
} from '@bast/shared-styles/components';
Pill¶
Base pill/chip primitive for non-status labels with tokenized sizing.
Props¶
| Prop | Type | Default | Description |
|---|---|---|---|
size |
'sm' \| 'md' \| 'lg' |
'sm' |
Size token (sm = 10px baseline) |
label |
string |
- | Optional text label |
icon |
React.ElementType |
- | Optional icon component |
iconColor |
string |
- | Optional icon color override |
className |
string |
- | Color/background/border classes |
Example¶
import { Pill } from '@bast/shared-styles/components';
<Pill size="sm" className="bg-[var(--bg-elevated)] text-[var(--text-secondary)]">
Using defaults
</Pill>
StatusPill¶
Semantic status pill built on top of Pill and tone tokens.
Props¶
| Prop | Type | Default | Description |
|---|---|---|---|
tone |
StatusTone |
- | Semantic tone token |
label |
string |
- | Optional label text |
size |
'sm' \| 'md' \| 'lg' |
'sm' |
Shared pill size token |
emphasis |
'solid' \| 'soft' \| 'outline' |
'solid' |
Visual emphasis |
variant |
'solid' \| 'soft' \| 'outline' |
- | Alias for emphasis (compat) |
icon |
React.ElementType |
- | Optional icon component |
Example¶
import { StatusPill } from '@bast/shared-styles/components';
<StatusPill tone="success" variant="soft">Enabled</StatusPill>
ThemeLifecyclePill¶
Theme lifecycle status primitive for CAT Builder and version-management screens.
Props¶
| Prop | Type | Default | Description |
|---|---|---|---|
status |
'draft' \| 'pending' \| 'active' \| 'archived' |
- | Lifecycle status value |
size |
'sm' \| 'md' \| 'lg' |
'md' |
Shared pill size token |
labelOverride |
string |
- | Optional custom display label |
Example¶
import { ThemeLifecyclePill } from '@bast/shared-styles/components';
<ThemeLifecyclePill status="active" />
ThemeVersionPill¶
Version label primitive for versioned table/list rows.
Props¶
| Prop | Type | Default | Description |
|---|---|---|---|
version |
number \| string |
- | Version identifier |
size |
'sm' \| 'md' \| 'lg' |
'md' |
Shared pill size token |
prefix |
string |
'v' |
Prefix for rendered value |
Example¶
IconActionButton¶
Compact circular icon button for dense row actions in management tables.
Props¶
| Prop | Type | Default | Description |
|---|---|---|---|
icon |
ReactNode |
- | Icon element to render |
tone |
'neutral' \| 'success' \| 'warning' \| 'danger' |
'neutral' |
Semantic action tone |
disabled |
boolean |
false |
Disable interaction |
Example¶
import { IconActionButton } from '@bast/shared-styles/components';
import { Pencil } from 'lucide-react';
<IconActionButton icon={<Pencil className="h-4 w-4" />} aria-label="Edit theme" />
Accessibility¶
All components are built with accessibility in mind:
- Proper ARIA attributes
- Keyboard navigation support
- Focus states with visible outlines
- Screen reader compatible labels
- Color contrast compliant (WCAG 2.1)
Combining Components¶
import { NeuCard, NeuButton, NeuInput, NeuAlert } from '@bast/shared-styles/components';
function LoginForm() {
const [error, setError] = useState<string | null>(null);
return (
<NeuCard className="p-6 max-w-md mx-auto">
<h2 className="text-xl font-medium text-[var(--primary-text)] mb-4">
Sign In
</h2>
{error && (
<NeuAlert
variant="error"
title="Login Failed"
message={error}
className="mb-4"
dismissible
onDismiss={() => setError(null)}
/>
)}
<form className="space-y-4">
<NeuInput
label="Email"
type="email"
placeholder="you@example.com"
/>
<NeuInput
label="Password"
type="password"
placeholder="••••••••"
/>
<NeuButton variant="success" fullWidth type="submit">
Sign In
</NeuButton>
</form>
</NeuCard>
);
}
Additional Components (March 2026)¶
The following components were added or promoted to shared-styles as part of the Tailwind-to-CSS migration. All use CSS classes from src/utilities/*.css — no Tailwind utility classes.
NeuTabNav¶
Tab bar container for navigation tabs.
<NeuTabNav>
<button className="neu-tab active">Overview</button>
<button className="neu-tab">Settings</button>
</NeuTabNav>
StatusDot¶
Small colored dot indicating status, using the statusTone system.
| Prop | Type | Default | Description |
|---|---|---|---|
tone |
StatusTone |
- | Color tone from the status tone palette |
size |
'sm' \| 'md' \| 'lg' |
'sm' |
Dot diameter (8px / 12px / 16px) |
DetailScreenHeader¶
Sticky header for detail/edit screens with back button, title (optionally as a dropdown switcher), badges, and right-side actions.
| Prop | Type | Default | Description |
|---|---|---|---|
onBack |
() => void |
- | Navigate back handler |
title |
string |
- | Screen title |
dropdownContent |
ReactNode |
- | If provided, title becomes a dropdown trigger |
dropdownAriaLabel |
string |
'Select item' |
Accessible label for dropdown |
badges |
ReactNode |
- | Status badges next to title |
actions |
ReactNode |
- | Right-side action buttons |
<DetailScreenHeader
onBack={() => navigate(-1)}
title="Knowledge Base"
badges={<StatusPill label="Active" tone="success" />}
actions={<Button variant="neu-secondary">Edit</Button>}
/>
IconActionButton¶
Small circular icon button with tone variants.
| Prop | Type | Default | Description |
|---|---|---|---|
icon |
ReactNode |
- | Icon element to render |
tone |
'neutral' \| 'success' \| 'warning' \| 'danger' |
'neutral' |
Color tone |
aria-label |
string |
- | Required accessible label |
CSS-only rule: All shared-styles components use CSS classes from
src/utilities/or inline styles with CSS variable tokens. Seepackages/shared-styles/CONTRIBUTING.mdfor details.