Component mappings in React involve creating .mapper.tsx
or .mapper.jsx
files that connect Figma components to your React code components. These mappings define how Figma component properties translate to React component props.
A component mapping file links a specific Figma component to a React component in your codebase. To identify the Figma component, you can use either:
componentKey
: A unique identifier for the Figma componenturl
: The Figma URL that points to the component (more human-readable)
Both methods achieve the same result, but the URL approach is often more convenient for manual creation.
These mapping files are just normal files in your repository that can be created manually. However, for convenience, we also provide a CLI command to generate them more easily with AI assistance.
Once this files exist in your project, we use npx builder.io@latest figma publish
to publish them to your Builder Space.
The CLI provides a more convenient approach with AI assistance to help you bootstrap mappings more quickly. Note that either approach, manual or CLI, lead to the same result, creating [componentName].mapper.tsx
files in your project.
The CLI-based workflow leverages AI to automatically generate appropriate mappings between your Figma designs and code components. It analyzes the Figma component, your code components, and any additional documentation to figure out the best mapper function.
To complete the mapping process, do the following:
Use the Builder Figma Plugin
Open the Builder Figma Plugin and navigate to the Design System tab. The plugin scans your selection and identifies unmapped components.
Select components in Figma
Select the components you want to map to your code components.
Generate the CLI command
In the Design System tab of the plugin, you'll see a list of unmapped components along with a CLI command. This command includes the Figma IDs for all unmapped components. Copy this command by clicking the copy icon.
# Example command
npx builder.io@latest figma generate --token [TOKEN]
Run the command
Open your terminal in your project directory and paste the command. When you run it, the CLI will:
- Look up the Figma components based on their IDs
- Scan your codebase for potential matching components
Select local components
The CLI will display a list of code components found in your project and prompt you to select which ones should be mapped to your Figma components. Use the arrow keys to navigate and press Enter to select a component.
Select a code component to map ❖ PrimaryButton
❯ ★ Button from '@/components/ui/button'
Card from '@/components/ui/card'
⏭️ Skip (Ctrl+C)
🏗️ Scaffold Mapper (Generate interface only)
📦 External npm package
The CLI suggests the best matches first (marked with ★), based on name similarity. If your component is in an external package, select that option to choose from installed packages.
Add documentation (Optional)
The CLI will ask if you want to provide a documentation URL for your component. For optimal results, provide a URL to documentation that includes actual code examples showing how to use the component:
Providing a docs URL for Button can drastically improve results: (Ctrl+C to skip)
> https://mui.com/components/buttons/
Adding a documentation URL significantly improves the quality of generated mappings, as the AI can learn from the component’s official API documentation. For best results, provide URLs to pages that contain actual code examples of how to use the React component, showing props, event handlers, and common patterns.
Documentation with practical code samples is much more valuable than pages with only theoretical explanations or API references without examples.
Review AI-generated mappings
The CLI uses AI to suggest appropriate mappings between your Figma and code components. It will show you the suggested mapping code:
import { figmaMapping } from "@builder.io/dev-tools/figma";
import { Button } from "@/components/ui/button";
figmaMapping({
componentKey: "9ca66d3a1f5b2c4e7d8a0b9f",
mapper(figma) {
return (
<Button
variant={figma.Variant?.toLowerCase()}
size={figma.Size?.toLowerCase()}
disabled={figma.State === "Disabled"}
>
{figma.$textContent || figma.Text || "Button"}
</Button>
);
},
});
Refine the mapping
If needed, you can provide natural language feedback to improve the mapping:
How does the mapping look? Reply "good", or provide feedback (Ctrl+C to exit)
> The button should use figma.Label for the text content instead of $textContent
The AI will update the mapping based on your feedback and show you the revised code. You can continue this feedback loop until you’re satisfied with the mapping.
You can give specific instructions like “Map the ‘Color’ property to the ‘color’ prop” or “Use the first child as the icon.”
Save the mapping
Once you're satisfied with the mapping, the CLI will ask where to save it:
Where do you want to save the new mapping? (Ctrl+C to exit)
> src/mappings/Button.mapper.tsx
The default location is usually src/mappings/[ComponentName].mapper.tsx
, but you can specify any valid path within your project.
Publish the mapping
After creating one or more mappings, publish them to your Builder Space:
npx builder.io figma publish
This will display:
Searching for mapping files...
Found 3 mapping files
Validating mappings...
You are about to publish 3 mapping files to your Builder.io space.
Do you want to continue? (Y/n)
> Y
Publishing mappings to Builder.io...
✓ Published 3 mapping files successfully
Your mappings are now available in the Builder Figma plugin
If you encounter issues during the mapping process, review the following recommendations.
Component not found
If the CLI can't find your component, it will offer to scaffold a basic mapping:
No matching components found for 'CustomButton'.
Do you want to scaffold a basic mapping? (Y/n)
> Y
Authentication problems
If you encounter authentication issues, you can forcefully re-authenticate with the command:
npx builder.io figma auth --force
Mappings not working in Figma
Verify that the CLI and Figma plugin are using the same Builder.io space, and try republishing with the verbose flag, like so:
npx builder.io figma publish --verbose
TypeScript errors during publishing
If the publish command fails with TypeScript errors or validation issues, you can bypass these checks using the --force
flag:
npx builder.io figma publish --force
You’ll see a warning, but the CLI will proceed with publishing:
TypeScript errors in src/mappings/Button.mapper.tsx:
• Cannot find name 'ButtonProps'
• Property 'variant' does not exist on type '{}'
Local mappings contain some errors, but --force flag was used, skipping.
This is particularly useful when:
- You’re dealing with complex TypeScript types the CLI doesn’t understand
- The errors are in parts of the code that won’t affect the mapping functionality
- You need to publish quickly and plan to fix the issues later
While --force
allows you to publish despite errors, it’s best practice to fix the underlying issues when possible, as they might cause problems when using the Figma plugin.
Instead of relying on AI to generate the mapping, create the mapping file yourself by completing the following steps.
Create a mapper file
Create a file with the naming convention [componentName].mapper.tsx
in your project. Many developers use a dedicated mappings
directory to organize these files, for example: src/mappings/Button.mapper.tsx
.
Import required dependencies:
import { figmaMapping } from "@builder.io/dev-tools/figma";
import YourComponent from "@/path/to/your/component";
Define your mapping function:
This is where you’ll write the logic that transforms Figma properties into React component props. You need to identify your Figma component using the url
parameter:
// Using the URL approach (more human-readable)
figmaMapping({
url: "https://www.figma.com/file/abc123/Design-System?node-id=456:789",
mapper(figma) {
return (
<YourComponent prop1={figma.Property1} prop2={figma.Property2}>
{figma.$children}
</YourComponent>
);
},
});
The URL approach is often preferred for manual mapping because it’s more human-readable, easier to obtain directly from Figma, and provides a direct link back to the visual component.
Test your mapping
Run your local development server with Devtools enabled to test your mapping.
Publish your mapping
Use the CLI command to publish your manually created mapping:
npx builder.io figma publish
- Open your Figma design file
- Select the component you want to map
- Right-click on the selection
- Choose "Copy Link To Selection" from the context menu
- Paste the URL into your mapping file
While both componentKey
and url
methods work for identifying Figma components, the URL approach has several advantages when manually creating mappings:
- Ease of Access: You can easily obtain the URL directly from Figma's UI by right-clicking a component and selecting "Copy Link To Selection"
- Human Readability: URLs contain readable information about the Figma file name and design context, making them more maintainable
- Direct Reference: The URL provides a clickable link back to the exact component in Figma, making it easier to check the design when updating mappings
- Contextual Information: The URL contains information about the file structure and location of the component, which aids in documentation
The componentKey
approach, while less human-readable, is more concise and is what the CLI uses internally when generating mappings.
The mapping function has access to a rich set of properties and methods through the figma
parameter. These properties and methods are included below.
Returns an array of all direct child nodes of the current Figma design.
figmaMapping({
componentKey: "button-component-key",
mapper(figma) {
return <Button>{figma.$children}</Button>;
},
});
Retrieves the text content from the current Figma design node or its text children.
figmaMapping({
componentKey: "button-component-key",
mapper(figma) {
return <Button>{figma.$children[1].$textContent}</Button>;
},
});
Maps a specific child node of the current Figma component by its layer name.
figmaMapping({
componentKey: "dialog-component-key",
mapper(figma) {
return <div>{figma.$findOneByName("dialog")}</div>;
},
});
Finds the first node that meets specified criteria through a callback function.
figmaMapping({
componentKey: "page-component-key",
mapper(figma) {
return <div>{figma.$findOne((node) => node.name === "Heading")}</div>;
},
});
Traverses all child nodes and applies a function to each one.
figmaMapping({
componentKey: "content-component-key",
mapper(figma) {
return figma.$visit((node) => {
if (node.name === "Header") {
return <h1>{node.$textContent}</h1>;
} else if (node.name === "Content") {
return node.$textContent;
}
});
},
});
figmaMapping({
componentKey: "button-component-key",
mapper(figma) {
return (
<Button
color={figma.Color?.toLowerCase()}
size={figma.Size?.toLowerCase()}
type={figma.Variant?.toLowerCase()}
>
{figma.$children}
</Button>
);
},
});
figmaMapping({
componentKey: "hero-component-key",
mapper(figma) {
const heading = figma.Heading;
const supportingText = figma.$findOneByName("Supporting Text").$textContent;
const navigation = figma.$findOneByName("Navigation");
return (
<Hero
heading={heading}
supportingText={supportingText}
navigation={navigation}
/>
);
},
});
figmaMapping({
componentKey: "button-component-key",
mapper(figma) {
// Use the text from the 2nd child ($children is zero indexed)
const text = figma.$children[1].$textContent;
return <Button>{text}</Button>;
},
});
Another option is to retrieve children by their layer name:
figmaMapping({
componentKey: "button-component-key",
mapper(figma) {
const text = figma.$findOneByName("Label").$textContent;
return <Button>{text}</Button>;
},
});
figmaMapping({
componentKey: "button-component-key",
mapper(figma) {
// Make an array to hold the CSS class names
const classes = ["button"];
// If figma.variant is 'primary', add the 'button-primary' class
if (figma.variant === "primary") {
classes.push("button-primary");
}
// Return a button with className applied
return <button className={classes.join(" ")}>{figma.Text}</button>;
},
});
For complex layouts or special case handling, you can create a generic mapper:
figmaMapping({
genericMapper(figma) {
if (figma.$name === "Grid row") {
return <Grid>{figma.$children}</Grid>;
} else if (figma.$name === "Section") {
return <section>{figma.$children}</section>;
}
return undefined;
},
});
Here's a more complex example mapping a table component:
figmaMapping({
componentKey: "29938639a346fd304f89cbbdd9377064ac6426c1",
mapper(figma) {
// Extract columns data
const columns =
figma.$children?.map((column) => {
const header = column.$findOneByName("Header")?.$textContent ?? "";
return { name: header, uid: header.toLowerCase() };
}) ?? [];
// Extract rows data
const firstColumn = figma.$children?.[0];
const rowsFrame = firstColumn?.$findOneByName("Rows");
const rowCount = rowsFrame?.$children?.length ?? 0;
// Create rows data structure
const rows = Array.from({ length: rowCount }, (_, rowIndex) => {
const rowData = {};
figma.$children?.forEach((column) => {
const rowItem = column.$findOneByName("Rows")?.$children?.[rowIndex];
const cellContent =
rowItem?.$findOneByName("Row item")?.$textContent ?? "";
const columnId =
column.$findOneByName("Header")?.$textContent?.toLowerCase() ?? "";
rowData[columnId] = cellContent;
});
return { id: rowIndex, ...rowData };
});
return (
<TableView
aria-label="Table"
isQuiet={figma.Style === "Quiet"}
selectionMode={
figma["Selection Column"] === "True" ? "multiple" : "none"
}
>
<TableHeader columns={columns}>
{(column) => <Column>{column.name}</Column>}
</TableHeader>
<TableBody items={rows}>
{(item) => <Row>{(columnKey) => <Cell>{item[columnKey]}</Cell>}</Row>}
</TableBody>
</TableView>
);
},
});
For a complete end-to-end example of Figma component mappings in a real application, check out the Cloudscape Demo Repository. This repository showcases how to implement component mappings in a Next.js project with a real-world design system.
For more information on the available parameters and options for the figmaMapping
function, refer to the API Reference.
If you're working with Angular instead of React, check out the Creating Angular Mappings guide.