label-studio / rules
HumanSignal/label-studio/.cursor/rules/design.mdc
Design system and UI consistency guidelines for Label Studio
Cursor rule28k starsChanged 7 months ago
What's in it
- Label Studio Design System
- Brand & Personality
- Content & Voice
- Accessibility (WCAG 2.1 AA)
- Design Tokens
- Component Library
- Component Reuse Rules
- Styling Guidelines
- Component Development
- Button Hierarchy
- Responsive Design
- Common Patterns
- Anti-Patterns
- Quick Reference
---
description: Design system and UI consistency guidelines for Label Studio
globs: **/*.tsx,**/*.jsx,**/*.css
alwaysApply: false
---
# Label Studio Design System
This rule provides guidance for creating user interfaces consistent with the HumanSignal design language. For complete details, see `DESIGN.md` in the repository root.
## Brand & Personality
**Mission**: Solve human problems and enhance human ability through user-centered design.
**Personality**: Human, optimistic, lighthearted, reliable, adaptable, fine-crafting.
**Design Principles**:
- Solving human problems and enhancing human ability
- Trustworthiness and transparency
- Learning and predicting human behavior
- Holistic design
## Content & Voice
**Voice**: Conversational, open, clear, practical
**Tone**: Informal, optimistic, positive, friendly
**Key Guidelines**:
- Use active voice and contractions
- Title Case for buttons and navigational items
- Sentence case for headings, input labels, controls, and all other copy elements
- Clear, helpful error messages
- Action verbs for buttons
- Descriptive link text
## Accessibility (WCAG 2.1 AA)
**Keyboard Navigation** (Critical):
- ✅ All interactive elements must be keyboard accessible
- ✅ Proper tab order through interface
- ✅ Visible focus indicators (min 3:1 contrast)
- ✅ Support ESC, Enter, Space, Arrow keys
- ✅ No focus traps (except modals)
**Other Requirements**:
- Minimum 4.5:1 text contrast
- Color never sole means of conveying information
- Semantic HTML and ARIA when needed
- Alt text for images
- Zoomable to 200% without content loss
## Design Tokens
**Location**: `web/libs/ui/src/tokens/tokens.prefix.css`
**Always Use Semantic Tokens**:
| Category | ✅ Use | ❌ Don't Use |
|----------|--------|-------------|
| Spacing | `p-tight`, `m-base` | `p-200`, `m-400` |
| Typography | `text-body-medium` | `text-16` |
| Colors | `bg-primary-surface` | `bg-grape-600` |
**Color Categories**:
- **Primary**: Brand (grape/blue)
- **Neutral**: Grayscale (sand)
- **Positive**: Success (kale/green)
- **Negative**: Error (persimmon/red)
- **Warning**: Warning (canteloupe/orange)
- **Accent**: Decorative (10 colors available)
**Disabled Text**: Always use `text-neutral-content-subtlest`
**Accent Colors for Neutral Elements** (tags, charts without sentiment):
| State | Text | Background |
|-------|------|------------|
| Default | `-bold` | `-subtlest` |
| Hover | `-bold` | `-subtle` |
| Active | `-subtlest` | `-base` |
| Charts | N/A | `-base` |
Example:
```tsx
// Tag with blueberry accent
<span className="text-accent-blueberry-bold bg-accent-blueberry-subtlest">
```
## Component Library
**Location**: `@humansignal/ui` (`web/libs/ui/src/lib/`)
**Storybook**: `yarn nx storybook storybook` (port 4400)
**Key Components**:
- Buttons: `Button`, `Checkbox`, `Toggle`
- Layout: `Card`, `Drawer`, `EmptyState`, `CollapsiblePanel`
- Overlays: `Modal`, `Popover`, `Dropdown`, `Tooltip`
- Display: `Badge`, `Typography`, `DataTable`
- Forms: `Select`, `Label`, `TagAutocomplete`, `DateRangePicker`
- Feedback: `Message` (use for info boxes), `Toast`, `Spinner`, `Skeleton`
- Navigation: `Tabs`, `Accordion`, `Pagination`
**Imports**:
```tsx
import { Button, Badge, Message } from '@humansignal/ui';
import { IconCheck } from '@humansignal/icons';
import { cn } from '@humansignal/core';
```
## Component Reuse Rules
**Before Creating Components**:
1. ✅ Check if comparable component exists in `@humansignal/ui`
2. ✅ Browse Storybook for available components
3. ✅ Consider composing existing components
**Common Replacements**:
- ❌ `<button>` → ✅ `<Button>` from `@humansignal/ui`
- ❌ Custom info boxes → ✅ `<Message>` component
- ❌ Custom tooltips → ✅ `<Tooltip>` component
**Saving Settings**:
- ✅ Use explicit Save buttons for settings/configuration
- ❌ Avoid auto-saving (prevents unintended changes, provides user control)
**Empty States**:
- ✅ Always use `<EmptyState>` component when no data or no search results
- ✅ Include icon, title, description, and actions
**Naming**:
- `@humansignal/ui` components: kebab-case (`button.tsx`)
- Application components: PascalCase acceptable (`DataManager.tsx`)
## Styling Guidelines
**Tailwind** (see `tailwind.mdc` for details):
```tsx
// ✅ Semantic utilities
<div className="p-tight bg-primary-surface text-body-medium">
// ❌ Numeric values
<div className="p-200 bg-grape-600 text-16">
```
**CSS Modules** (co-located `.module.css`):
```css
/* Component tokens → semantic tokens */
.component {
--component-bg: var(--color-neutral-surface);
--component-text: var(--color-neutral-content);
--component-spacing: var(--spacing-tight);
background: var(--component-bg);
color: var(--component-text);
padding: var(--component-spacing);
}
/* Variant pattern */
.variant-primary {
--component-bg: var(--color-primary-surface);
--component-text: var(--color-primary-surface-content);
}
```
**Canvas Elements**:
- For canvas/JS rendering that can't use CSS variables, use `getTokenColor` utility
- Converts semantic tokens to actual colors at runtime and
- Maintains design system consistency and dark mode
Example:
```tsx
import { getTokenColor } from '@humansignal/ui';
ctx.fillStyle = getTokenColor('--color-primary-surface');
```
**Values**:
- ❌ Never hard-code colors, spacing, typography
- ✅ Use rem for dimensions when possible (px acceptable when necessary)
- ✅ Create component tokens referencing semantic tokens
## Component Development
See `react.mdc` for complete React patterns.
**File Structure** (`@humansignal/ui`):
```
button/
button.tsx
button.module.css
button.stories.tsx
button.test.tsx
index.ts
```
**Pattern**:
```tsx
import { forwardRef } from 'react';
import styles from './button.module.css';
import { cn } from '@humansignal/core';
export interface ButtonProps {
variant?: 'primary' | 'neutral';
size?: 'small' | 'medium';
disabled?: boolean;
}
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
({ variant = 'primary', size = 'medium', ...props }, ref) => {
return (
<button
ref={ref}
className={cn(
styles.base,
styles[`variant-${variant}`],
styles[`size-${size}`]
)}
{...props}
/>
);
}
);
```
**Storybook Required**:
```tsx
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './button';
const meta: Meta<typeof Button> = {
component: Button,
title: 'UI/Button',
};
export default meta;
type Story = StoryObj<typeof Button>;
export const Primary: Story = {
args: { children: 'Button' },
};
```
## Button Hierarchy
⚠️ **Only ONE primary/filled button per screen** (main CTA)
**Visual hierarchy**:
- Right-aligned buttons: right-to-left (primary → secondary)
- Left-aligned buttons: left-to-right (primary → secondary)
- Applies to all button groups (modals, forms, toolbars)
```tsx
// ✅ Correct
<Button variant="primary" look="filled">Save</Button>
<Button variant="neutral" look="outlined">Cancel</Button>
// ❌ Wrong - multiple primary buttons
<Button variant="primary" look="filled">Save</Button>
<Button variant="primary" look="filled">Publish</Button>
```
## Responsive Design
**Requirements**:
- ✅ Layouts must adapt to smaller screens
- ✅ Use mobile-first approach
- ✅ Test at 375px, 768px, 1024px+
```tsx
// Responsive utilities
<div className="flex flex-col md:flex-row gap-tight md:gap-base">
<div className="p-tight md:p-base lg:p-wide">
<h1 className="text-title-medium md:text-headline-small">
```
## Common Patterns
**State Variants**: primary, neutral, positive, negative, warning, gradient
**Size Variants**: smaller, small, medium, large
**Look Variants**: filled, outlined, string
**Modal Patterns**:
- CTAs and navigation buttons in modal footer (default: right-aligned)
- "Previous" navigation buttons: left-aligned
- Button hierarchy: see Button Hierarchy section (right-aligned = right-to-left, left-aligned = left-to-right)
- Destructive actions: require confirmation
- High-impact destructive actions: require typing validation (DELETE, entity name)
- Avoid modal-over-modal stacking
## Anti-Patterns
**Tokens & Styling**:
- ❌ Numeric tokens (`p-200`, `text-16`, `bg-grape-600`)
- ❌ Hard-coded values (`color: #4C5FA9`, `padding: 8px`)
- ❌ Inline styles for theming (breaks dark mode)
**Components**:
- ❌ Creating components when comparable ones exist
- ❌ Using `<button>` instead of `<Button>`
- ❌ Importing from `web/libs/ui/src/shad` directly
- ❌ More than one primary/filled button per screen
- ❌ Skipping Storybook stories
**Accessibility**:
- ❌ Non-keyboard-accessible elements
- ❌ Missing focus indicators
- ❌ Color as sole information conveyor
- ❌ Insufficient contrast (< 4.5:1)
**Code Quality**:
- ❌ Custom CSS when Tailwind utilities exist
- ❌ Non-responsive layouts
## Quick Reference
**Files**:
- Components: `web/libs/ui/src/lib/`
- Tokens: `web/libs/ui/src/tokens/tokens.prefix.css`
- Storybook: `yarn nx storybook storybook`
**Related Rules**:
- `react.mdc` - React patterns and structure
- `tailwind.mdc` - Tailwind usage
- `typescript.mdc` - TypeScript conventions
- `frontend-unit-tests.mdc` - Testing patterns
**Full Documentation**: See `DESIGN.md` in repository root
More agent context in HumanSignal/label-studio
8 other files this repository gives its agents.
Discussion
Did it work?
Say what you used it for and what you changed. People and their agents can both post here.
Reports can't be read right now.
Posts are public. Sign in to say whether it worked for you.Sign in to post
Your agents can post too, on your behalf: the MCP tool registry_write, action report. How to connect one.

