syntax-design-system
npx skills add https://github.com/cambly/syntax --skill syntax-design-system
Agent 安装分布
Skill 文档
Syntax Design System
Use this skill when working with Cambly’s Syntax design system components in React applications. Invoke this skill when:
- Implementing new UI features using Syntax components
- Converting existing UI to use Syntax components
- Fixing styling, accessibility, or component usage issues
- Reviewing code that uses Syntax components
Core Principles
When working with Syntax components, you must:
- Always use
Boxinstead of plain divs for layout and containers - Never hardcode spacing or colors – use the design system’s spacing scale (0-12) and color tokens
- Always provide
accessibilityLabelforIconButtoncomponents - Use semantic HTML via the
asprop (e.g.,<Box as="nav">) - Add
data-testidattributes for all interactive elements in tests
Installation
The Syntax packages required are:
@cambly/syntax-core– Main component library@cambly/syntax-design-tokens– Design tokens@cambly/syntax-icons– Icon components@cambly/syntax-floating-components– Tooltips and popovers with Floating UI
npm install @cambly/syntax-core @cambly/syntax-design-tokens @cambly/syntax-icons @cambly/syntax-floating-components
Component Selection Guide
Use this decision tree to select the right component:
Layout & Containers:
- Layout container â
Box(with flexbox props) - Content container with elevation â
Card
Buttons & Actions:
- Button with text â
Button - Button with icon only â
IconButton(requiresaccessibilityLabel) - Link styled as button â
LinkButton - Clickable area without button semantics â
TapArea - Group related buttons â
ButtonGroup
Typography:
- Body text, labels, captions â
Typography - Page/section headings â
Heading(with properasprop: h1-h6)
Form Inputs:
- Single-line text â
TextField - Multi-line text â
TextArea - True/false selection â
Checkbox - One of many options â
RadioButton - Dropdown selection â
SelectList(native) orRichSelectList(styled)
Feedback & Overlays:
- Blocking dialog â
Modal - Contextual overlay â
Popover - Temporary notification â
Toast - Hover information â
Tooltip
Indicators & Status:
- Small status indicator â
Badge - User profile image â
AvatarorAvatarGroup - Filter/tag â
Chip - Visual separator â
Divider - Icons â
Icon(use with@cambly/syntax-icons)
Navigation:
- Tab interface â
TabswithTabButtonorTabLink
Required Patterns
Box Component – The Foundation
Basic Layout:
<Box
display="flex"
direction="column"
gap={4}
justifyContent="center"
alignItems="start"
>
{children}
</Box>
Responsive Layout (mobile-first):
<Box
direction="column" // Mobile: stack vertically
smDirection="row" // Tablet (480px+): horizontal
lgDirection="row" // Desktop (960px+): horizontal
padding={2}
smPadding={4}
lgPadding={6}
>
{children}
</Box>
Spacing (0-12 scale):
<Box
margin={4} // All sides
marginTop={2} // Individual sides
marginStart={3} // Start (left in LTR, right in RTL)
padding={4}
paddingX={6} // Horizontal
paddingY={2} // Vertical
>
Semantic HTML:
<Box as="section" role="main"> // Renders as <section>
<Box as="nav"> // Renders as <nav>
Size Variants
Buttons/IconButtons/Chips: "sm" | "md" | "lg" (heights: 32px, 48px, 64px)
<Button text="Click me" size="md" />
Typography/Heading: 100 | 200 | 300 | 400 | 500 | 700 | 800 | 900 | 1100
<Typography size={400}>Body text</Typography>
<Heading size={600}>Page title</Heading>
Icon: 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | 1000
<Icon path={iconPath} size={400} />
Color System
Button Colors:
primary– Main call-to-action (blue)secondary– Secondary actions (gray)tertiary– Tertiary actions (minimal)destructive-primary/secondary/tertiary– Dangerous actions (red)success-primary/secondary/tertiary– Positive actions (green)branded– Brand-specific color
<Button text="Delete" color="destructive-primary" />
<Button text="Cancel" color="secondary" />
Background Context (on prop):
<Button text="Click" on="darkBackground" />
<TextField label="Name" on="lightBackground" />
Universal Colors (Box, Icon, Typography):
- Primary:
primary,primary100–primary900 - Semantic:
success100–success900,destructive100–destructive900 - Neutrals:
gray10–gray900,white,black - Brand:
sky,navy,teal,lilac,pink,cream
<Box backgroundColor="gray10" />
<Typography color="primary700">Text</Typography>
<Icon color="success500" size={300} />
Form Patterns
TextField with validation:
<TextField
label="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
error={!!emailError}
errorText={emailError}
helperText="We'll never share your email"
disabled={isSubmitting}
data-testid="email-input"
/>
Checkbox:
<Checkbox
label="I agree to terms"
checked={agreed}
onChange={(e) => setAgreed(e.target.checked)}
error={submitted && !agreed}
size="md"
/>
RadioButton group:
{
options.map((option) => (
<RadioButton
key={option.value}
label={option.label}
checked={selected === option.value}
onChange={() => setSelected(option.value)}
name="options"
/>
));
}
Button Patterns
Button with icons:
import { ChevronRightIcon } from "@cambly/syntax-icons";
<Button text="Continue" endIcon={ChevronRightIcon} color="primary" size="lg" />;
Loading state:
<Button
text="Save"
loading={isSubmitting}
loadingText="Saving..."
disabled={!isDirty}
/>
IconButton (REQUIRED: accessibilityLabel):
import { CloseIcon } from "@cambly/syntax-icons";
<IconButton
icon={CloseIcon}
accessibilityLabel="Close dialog" // REQUIRED!
color="secondary"
size="sm"
onClick={handleClose}
/>;
Typography Patterns
// Headings - always use semantic 'as' prop
<Heading as="h1" size={800}>Page Title</Heading>
<Heading as="h2" size={600}>Section Heading</Heading>
// Body text
<Typography size={400}>Regular paragraph text</Typography>
<Typography size={300} color="gray700">Secondary text</Typography>
// Text styling
<Typography
weight="semiBold"
transform="uppercase"
align="center"
lineClamp={2} // Truncate after 2 lines
>
Content
</Typography>
Modal & Dialog Pattern
<Modal isOpen={isOpen} onDismiss={handleClose} title="Confirm Action" size="md">
<Box padding={6}>
<Typography>Are you sure?</Typography>
<Box display="flex" gap={2} marginTop={4}>
<Button text="Cancel" color="secondary" onClick={handleClose} />
<Button text="Confirm" color="primary" onClick={handleConfirm} />
</Box>
</Box>
</Modal>
Tooltip Pattern
<Tooltip text="Additional information">
<IconButton icon={InfoIcon} accessibilityLabel="Info" />
</Tooltip>
Card Pattern
<Card size="medium" backgroundColor="white">
<Box padding={4}>
<Heading size={500}>Card Title</Heading>
<Typography size={300} color="gray700">
Card content goes here
</Typography>
</Box>
</Card>
Accessibility Requirements
Required Props
Form inputs need labels:
<TextField label="Email" /> // Good
<Checkbox label="I agree" /> // Good
Icon buttons need accessibilityLabel:
<IconButton
icon={TrashIcon}
accessibilityLabel="Delete item" // Required for screen readers
/>
Use semantic HTML:
<Box as="nav"> // Semantic elements
<Box as="main">
<Heading as="h1"> // Proper heading hierarchy
Focus Management
- Components automatically handle keyboard focus visibility
- Focus outlines only appear on keyboard navigation (not clicks)
- All interactive elements are keyboard accessible
Form Accessibility
// Associate helper text with input
<Box>
<TextField label="Password" aria-describedby="password-help" />
<Typography id="password-help" size={200}>
Must be at least 8 characters
</Typography>
</Box>
Common Mistakes to Avoid
â Using plain divs for layout
// BAD
<div style={{ display: 'flex', gap: '16px' }}>
â Use Box component
// GOOD
<Box display="flex" gap={4}>
â Missing accessibilityLabel
// BAD - inaccessible
<IconButton icon={CloseIcon} />
â Always include accessibilityLabel
// GOOD
<IconButton icon={CloseIcon} accessibilityLabel="Close" />
â Hardcoded pixel values
// BAD
<Box style={{ marginTop: '24px' }}>
â Use spacing scale
// GOOD - uses 0-12 scale (6 = 24px)
<Box marginTop={6}>
â Wrong icon imports
// BAD
import CloseIcon from "@cambly/syntax-icons/CloseIcon";
â Named imports from package root
// GOOD
import { CloseIcon } from "@cambly/syntax-icons";
â Ignoring background context
// BAD - button on dark background with wrong styling
<Box backgroundColor="navy">
<Button text="Click me" />
</Box>
â Use ‘on’ prop for contrast
// GOOD
<Box backgroundColor="navy">
<Button text="Click me" on="darkBackground" />
</Box>
â Avoid âself-spacingâ children
// BAD
<Box marginBottom={2}>Some text</Box>
<Box marginBottom={2}>Some more text</Box>
â Use a parent wrapper to define sibling spacing
// GOOD
<Box display="flex" direction="column" gap={2}>
<Box>Some text</Box>
<Box>Some more text</Box>
</Box>
```
#### When child margins are OK
Use margins on a component only when it is intrinsic to that component, not dependent on neighbors (e.g., internal spacing within the component, or a visual affordance that always exists regardless of placement).
## Import Patterns
```typescript
// Core components
import { Box, Button, Typography, TextField } from "@cambly/syntax-core";
// Icons (named imports only)
import { ChevronRightIcon, CloseIcon, CheckIcon } from "@cambly/syntax-icons";
// Floating components
import { FloatingTooltip } from "@cambly/syntax-floating-components";
// Design tokens (rarely needed directly)
import { tokens } from "@cambly/syntax-design-tokens";
Testing
Always add data-testid for testable elements:
<Button
text="Submit"
data-testid="submit-button"
onClick={handleSubmit}
/>
<TextField
label="Email"
data-testid="email-input"
value={email}
/>
Theme Provider
Wrap your app root with ThemeProvider:
import { ThemeProvider } from "@cambly/syntax-core";
function App() {
return <ThemeProvider>{/* Your app */}</ThemeProvider>;
}
Review Checklist
When reviewing or writing code with Syntax components, verify:
- Using
Boxinstead of plain divs for layout - Using spacing scale (0-12) instead of hardcoded pixels
- All
IconButtoncomponents haveaccessibilityLabel - Form inputs have labels
- Using semantic HTML via
asprop where appropriate - Icons imported correctly from
@cambly/syntax-icons -
onprop used for components on dark backgrounds -
data-testidadded to interactive elements - Proper heading hierarchy with
Headingcomponent - Responsive props used for mobile-first design
Additional Resources
- Storybook documentation: Run
pnpm startin the syntax repo - Component props: TypeScript types provide full documentation
- All components have full TypeScript type definitions