Ruletypescript

Figma Component Rule

paths:

View Source

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:

  1. Analyze: Call figma_get_design_context and figma_get_screenshot
  2. Extract tokens: Call figma_get_variable_defs for EACH state (Default, Hover, Focus, Disabled, Error)
  3. 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_context alone without figma_get_variable_defs for each state
  • Copying patterns from similar components without verifying Figma
  • Adding props/features not in design
  • Ignoring nested component layers