Learn more about atomic design principles and how to apply them in your work. Visit the Brad Frost's Atomic Design website for a comprehensive guide.
The history of human-computer interaction and user interface design (graphical user interface, GUI) spans over 70 years. There were only text-based command-line interfaces available when it was initially launched in the early 1960s. We first saw the mouse, windows, icons, and hypertext links when Douglas Engelbart unveiled the "Mother of All Demos.”
Douglas Engelbart using the NLS’s 5-button chord keyset, a standard QWERTY keyboard, and 3-button mouse, around 1968. NMAH Catalog #2015.3073.11.
This marked the start of a lengthy history of user interface design, which was followed by some incredible successes like Xerox PARC’s Alto (’73) and Star (’81), Apple Lisa (’83) and Macintosh (’84), Microsoft Windows (’85). The development of standardized, user-friendly, and reusable interfaces became necessary as a result of all these technical advancements.
Macintosh System 1 GUI (1984)
When UI became dynamic with Web 2.0 tech in the early 2000s, designers started to create reusable snippets (navigation elements, modals, form elements). This led to emerging design patterns like Yahoo did back in 2006 with Yahoo Design Pattern Library (YUI). Facebook released React in 2013, marking a significant advancement in UI architecture and contributing to the growth of the component ecosystem. Today's digital products are composed of tens of thousands of uniform, scalable, and reusable components. Because it must fit in multiple locations on the interface, designing a small square with an optional checkmark within takes additional planning effort. Since designers and developers co-own modern UI components, we designers need to learn more about their technical implementation.
Placeholder
A decade ago, UI designers relied on Photoshop for interface design. In the 2010s, Sketch emerged as a Mac-exclusive option, though its paid model limited widespread adoption. Many of us started with Adobe XD, which introduced component concepts but lacked robust property management. Tools like InVision, Origami Studio, and Axure RP existed but proved too complex for junior designers.
Button, Tag, and Icon-Button components
A component is a single, reusable UI element within a product, a building block that can be used repeatedly with different configurations. This concept mirrors both design systems and code architecture.
Learn more about atomic design principles and how to apply them in your work. Visit the Brad Frost's Atomic Design website for a comprehensive guide.
Despite syntactic differences, all modern JavaScript frameworks share a common component-based architecture:
Placeholder
When you design components with these universal concepts in mind, your work translates smoothly across any framework. A well-designed button in Figma becomes an equally well-implemented button in React, Vue, Angular, or Svelte.
Properties (props) define a component's identity and characteristics. Consider a car analogy: it has properties like brand, model, year, and passenger capacity where each serves a specific purpose.
Button component with different property configurations
Similarly, a button component might have properties like:
label
(string) : The button texttype
(variant) : primary | secondary | tertiarysize
(variant) : small | medium | largeisDisabled
(boolean) : Whether the button is interactiveisLoading
(boolean) : Shows loading spinnerstartIcon
(component instance) : Optional icon before textendIcon
(component instance) : Optional icon after textonClick
(action) : What happens when clickedTry Button component properties on the Storybook Playground
These properties map directly to React/Vue/Angular/Svelte props and make components flexible, reusable, and maintainable.
Designing components that developers can efficiently implement requires mastering four fundamental principles:
Let's explore each principle in depth.
In this section, we'll cover best practices for structuring components using Auto-Layout in Figma and naming conventions that translate seamlessly to HTML/CSS.
Figma offers two ways to nest objects: Groups and Frames. Groups are the traditional Adobe-style approach, while Frames unlock Figma's powerful Auto-Layout feature.
Placeholder
Auto-Layout in Figma directly corresponds to CSS Flexbox properties. When you configure Auto-Layout settings in Figma, you're essentially defining:
display: flex
or display: inline-flex
flex-direction: row
or flex-direction: column
justify-content
and align-items
valuesgap
for spacing between childrenpadding
for internal spacingwidth: auto
(hug contents) or width: 100%
(fill container)Placeholder
Learn more about Figma Auto-Layout and how it maps to CSS Flexbox. Visit the Figma Help Center for a comprehensive guide.
Key principle:
Your frame structure defines the HTML structure. Each frame typically becomes an HTML element (most commonly a <div>
container, but could be <button>
, <section>
, <header>
, <nav>
, or <article>
depending on semantic meaning). Therefore, using the minimum necessary frames helps developers create cleaner, more maintainable code.
Best practices:
A simple button needs only one or two frames:
ButtonContainer (Frame with Auto-Layout) ├── padding: 12px 24px ├── gap: 8px ├── direction: horizontal ├── align: center ├── width: hug contents │ ├── StartIcon (optional, component instance) ├── ButtonLabel (text) └── EndIcon (optional, component instance)
This structure translates directly to HTML/CSS:
/// HTML <button className="button"> {/* if startIcon present */} <span>Click me</span> {/* if endIcon present */} </button>
/// CSS .button { display: flex; flex-direction: row; align-items: center; gap: 8px; padding: 12px 24px; width: fit-content; }
Proper layer naming is essential for clear communication between designers and developers. Meaningful names help developers understand the purpose of each frame and how it maps to code. If you wouldn't name a CSS class "Frame 1" or "Group 2", don't use those names in your layers. Instead, use descriptive names that reflect the element's role.
Unnamed vs Meaningful Layer Names for a Card Component
Above example shows a card component with poorly named layers (left) versus thoughtfully named layers (right). The meaningful names clarify the structure and purpose of each element, making it easier for developers to implement the design accurately. Even the Figma icons tells the layout direction (horizontal vs vertical) at a glance.
Figma provides AI-powered layer naming if you prefer not to manually label frames. Learn more about using AI to rename layers in Figma.
Benefits of Thoughtful Layer Naming
Naming Conventions
Follow these guidelines when naming layers:
/// Use clear, descriptive names 🟩 CardImage (not Image1) 🟩 CardTitle (not Text_Layer_2) 🟩 ActionButton (not Button) 🟩 IconWrapper (not Group_23) 🟩 PriceLabel (not Text)
/// Do not use vague, generic names 🟥 Container 🟥 Wrapper 🟥 Group 🟥 Frame #123456 🟥 Text
Do not use Rectangle and Ellipse in Figma since they do not translate to semantic HTML elements. Always use Frames with Auto-Layout for containers. Learn more about Groups vs Frames in Figma.
By combining proper Auto-Layout structure with meaningful layer names, you set developers up for success—enabling them to implement components quickly and accurately. Modern design systems like Material Design (Google), Carbon (IBM), and Atlassian Design System use consistent layer naming to create clarity across hundreds of components.
Properties of the button component in Figma UI
Component properties (props) are arguably Figma's most powerful feature for creating flexible, functional components that mirror real component behavior. As a designer, If I am going to use an UI element more than once, I always create a component with well-defined properties. This approach not only streamlines my design process but also significantly reduces the development effort required to implement the component. Defining properties is a time investment that pays off in spades.
Figma supports several property types that map directly to JavaScript/TypeScript:
Property types available in Figma
Figma Property | Frontend Equivalent | Example Use Case |
---|---|---|
Text | string | Button labels, card titles, descriptions |
Boolean | boolean | isDisabled, isLoading, hasIcon |
Instance Swap | Component instance | Icon components, avatar images |
Variant | string enum | type="primary", size="large" |
Table 1. Mapping Figma Properties to Frontend Equivalents
Property Naming Best Practices
While naming properties, consider giving meaningful names that convey the purpose of the property. Following front-end conventions can help maintain consistency and clarity and it also reduce the development time. Adding a ? at the end of boolean properties indicates that the property is optional which is a valuable info for the development team.
/// Use descriptive, purposeful names 🟩 cardTitle 🟩 isDisabled 🟩 buttonLabel 🟩 iconStart 🟩 hasEndIcon 🟩 showKebabMenu
/// Do not use vague, generic names 🟥 text1 🟥 disabled 🟥 label 🟥 icon 🟥 end 🟥 menu
Follow frontend conventions
Front-end development is in progress since the early 2000s. Over the years, certain conventions have emerged that enhance code readability and maintainability. Adopting these conventions in your property naming can significantly improve collaboration with developers. As designers, we should strive to speak the same language as our developer counterparts. Here are some key conventions to consider:
Learn more about JavaScript naming conventions and best practices. Visit the W3Schools website for a comprehensive guide.
Framework-Specific Implementation
The same Figma component properties translate naturally across frameworks. Here's how a button component with well-named props looks in different ecosystems:
Component property mapping between Figma and code
Above Figma button component properties map directly to props in React, Vue, Angular, and Svelte with minimal adjustments for framework syntax. This consistency reduces cognitive load for developers and help them implement components faster and with fewer errors.
/// React (TypeScript) interface ButtonProps { label: string; size?: 'small' | 'medium' | 'large'; type?: 'primary' | 'secondary' | 'tertiary'; isLoading?: boolean; isDisabled?: boolean; endIcon?: React.ReactNode; startIcon?: React.ReactNode; onClick?: () => void; } // Usage <Button label="Click me" type="primary" size="medium" isDisabled={false} startIcon={<WestRoundedIcon />} onClick={() => { /* handle click */ }} />
/// Vue 3 (TypeScript) interface ButtonProps { label: string; type?: 'primary' | 'secondary' | 'tertiary'; size?: 'small' | 'medium' | 'large'; isDisabled?: boolean; isLoading?: boolean; startIcon?: Component; endIcon?: Component; } // Usage <Button label="Click me" type="primary" size="medium" :is-disabled="false" :start-icon="ArrowLeft" @click="handleClick" />
/// Angular (TypeScript) @Component({ selector: 'app-button', template: '' }) export class ButtonComponent { @Input() label!: string; @Input() type?: 'primary' | 'secondary' | 'tertiary' = 'primary'; @Input() size?: 'small' | 'medium' | 'large' = 'medium'; @Input() isDisabled?: boolean = false; @Input() isLoading?: boolean = false; @Input() startIcon?: TemplateRef<any>; @Input() endIcon?: TemplateRef<any>; @Output() onClick = new EventEmitter<void>(); } // Usage <app-button label="Click me" type="primary" size="medium" [isDisabled]="false" [startIcon]="arrowLeftTemplate" (onClick)="handleClick()" />
/// Svelte (TypeScript) <script lang="ts"> export let label: string; export let type: 'primary' | 'secondary' | 'tertiary' = 'primary'; export let size: 'small' | 'medium' | 'large' = 'medium'; export let isDisabled: boolean = false; export let isLoading: boolean = false; export let startIcon: Component | undefined = undefined; export let endIcon: Component | undefined = undefined; </script> // Usage <Button label="Click me" type="primary" size="medium" isDisabled={false} startIcon={ArrowLeft} on:click={handleClick} />
As we can see, the same well-defined properties in Figma translate cleanly to props in React, Vue, Angular, and Svelte. This consistency not only speeds up development but also reduces the likelihood of miscommunication or errors during implementation. By investing time in defining clear, js-friendly component properties in Figma, we set the stage for a smoother handoff to developers and a more efficient development process overall.
Sample design tokens which point to a color hex value (#0D99FF), spacing in pixels (16px), font family (Space Grotesk), and border radius (8px).
Modern digital products require theme support (light mode, dark mode, high contrast). This necessitates tokenization, using variables instead of hard-coded values. Besides that, using tokens instead of fixed values also enables scalability and consistency across the design system. For example, if your brand color changes, updating a single token updates it everywhere. As designers, we often hear new iteration ideas from stakeholders. Using tokens allows us to implement changes quickly without redesigning every component.
From Hard-Coded Values to Design Tokens
If you are using CSS or CSS-in-JS, design tokens are typically implemented as CSS variables (custom properties). You need to create your own primitive and component tokens. If you want to skip the creating primitive tokens, it's best to use an existing open-source token library like TailwindCSS. Tailwind provides a comprehensive set of design tokens that cover colors, spacing, typography, and more. You can then create component-specific tokens that reference these primitives. For example, a button's primary background color token might reference Tailwind's `--tw-color-blue-600`. Here is an example of how to transition from old way to modern way:
/// Old approach (hard-coded values) 🟥 Color: "#0D99FF" (specific hex value) 🟥 Spacing: "16px" (specific pixel value) 🟥 Font: "Inter" (specific typeface) 🟥 Border radius: "8px" (specific value)
/// Modern approach (design tokens) 🟩 Color: "--color-primary-600" → resolves to "#0D99FF" in light mode, "#3B82F6" in dark mode 🟩 Spacing: "--spacing-4" → resolves to "16px" (or "1rem" in fluid systems) 🟩 Font: "--font-family-sans" → resolves to "Inter, system-ui, sans-serif" 🟩 Border radius: "--radius-md" → resolves to "8px"
Benefits of Tokenization
Figma's Local Variables feature enables comprehensive tokenization:
Our goal was to improve account security with an additional layer of authentication—without creating friction or drop-off in user experience. We needed a solution that served both our individual (B2C) users and our enterprise clients with scalable and customizable options.
Table of Contents