Ruletypescript
Figma Component Rule
paths:
Figma-to-Code Component Guidelines
When building EDS 2.0 components from Figma designs, follow this workflow.
MCP Workflow
If Figma MCP tools are available, use this workflow:
- Analyze: Call
figma_get_design_contextandfigma_get_screenshot - Extract tokens: Call
figma_get_variable_defsfor EACH state (Default, Hover, Focus, Disabled, Error) - Implement: Create component files using extracted tokens
File Structure
ComponentName/
index.ts # Named exports only
ComponentName.tsx # forwardRef component
ComponentName.types.ts # Types with JSDoc
componentname.css # Vanilla CSS + BEM + tokens
ComponentName.figma.tsx # Figma Code Connect
ComponentName.test.tsx # Jest + Testing Library + jest-axe
ComponentName.stories.tsx
Component Pattern
import { forwardRef, useId } from 'react'
import type { ComponentProps } from './Component.types'
import './component.css'
export const Component = forwardRef<HTMLElement, ComponentProps>(
function Component({ className, ...rest }, ref) {
const classes = ['component', className].filter(Boolean).join(' ')
return <div ref={ref} className={classes} {...rest} />
},
)
Types Pattern
export type ComponentProps = {
/** Description for prop */
variant?: 'primary' | 'secondary'
} & HTMLAttributes<HTMLElement>
CSS Pattern
.component {
color: var(--eds-color-text-primary);
}
.component[data-variant='secondary'] {
color: var(--eds-color-text-secondary);
}
Sub-Component Convention
Figma layers prefixed with special characters are nested sub-components. Use figma.nestedProps() in Code Connect:
figma.connect(Component, 'figma-url', {
props: {
disabled: figma.enum('State', { Disabled: true }),
inner: figma.nestedProps('InnerComponent', {
open: figma.enum('Open', { true: true }),
}),
},
example: ({ disabled, inner }) => (
<Component disabled={disabled} open={inner.open} />
),
})
Test Pattern
Organize with describe blocks: Rendering, Accessibility, Behavior.
import { render, screen } from '@testing-library/react'
import { axe } from 'jest-axe'
import { Component } from '.'
describe('Component (next)', () => {
describe('Accessibility', () => {
it('passes axe', async () => {
const { container } = render(<Component />)
expect(await axe(container)).toHaveNoViolations()
})
})
})
Critical Rules
- Use EXACT variable names from
figma_get_variable_defs - Never assume tokens based on semantics
- Never hardcode hex values - always use CSS variables
- No default exports (except stories)
- WCAG 2.1 AA required
- Query priority: getByRole > getByLabelText > getByText > getByTestId
Anti-patterns
- Using
figma_get_design_contextalone withoutfigma_get_variable_defsfor each state - Copying patterns from similar components without verifying Figma
- Adding props/features not in design
- Ignoring nested component layers