Intro
Figma node can be exported to a new Angular component even with no configuration at all. There are 3 simple steps to achieve that:
Copy the result, download it, or deploy it to CodeSanbox
There are three examples on this page:
Example #1 - Export a simple Frame
Example #2 - Export a component with variants or building your design system
Example #3 - Export a Frame with Components
Example #1 - Export a simple Frame
First, let's try to export a simple frame that has no other components inside. Our test frame looks like this:
Now let's open Figmular and select the Notifications frame. It should generate the following code:
Html TypeScript CSS
Copy // notifications.component.html
<div class="notifications__1-59">
<div class="tags-panel__1-50">
<span class="text-tags-__1-49">Tags:</span>
<div class="simple-chip__1-43">
<span class="text-tag-1__1-44">Tag 1</span>
</div>
<div class="simple-chip__1-45">
<span class="text-tag-2__1-46">Tag 2</span>
</div>
<div class="simple-chip__1-47">
<span class="text-tag-3__1-48">Tag 3</span>
</div>
</div>
<div class="text-info__1-51">
<span class="text-header__1-52">Header</span>
<span class="text-desc__1-60"
>Long description for this block. This text should be wrapped to fit info
the width</span
>
</div>
</div>
Copy // notifications.component.ts
import { Component, Input } from "@angular/core";
@Component({
selector: "app-notifications",
templateUrl: "./notifications.component.html",
styleUrls: ["./notifications.component.scss"],
})
export class NotificationsComponent {}
Copy // notifications.component.scss
.notifications__1-59 {
padding-top: 8px;
padding-right: 8px;
padding-bottom: 8px;
padding-left: 8px;
display: flex;
flex-direction: column;
justify-content: flex-start;
flex-wrap: nowrap;
align-items: flex-start;
gap: 4px;
box-sizing: border-box;
border-radius: 0px;
border: 1px solid #c0caff;
background-color: #ffffff;
}
.tags-panel__1-50 {
padding-top: 8px;
padding-right: 8px;
padding-bottom: 8px;
padding-left: 8px;
display: flex;
flex-direction: row;
justify-content: flex-start;
flex-wrap: nowrap;
align-items: flex-start;
gap: 16px;
box-sizing: border-box;
border-radius: 4px;
border: 1px solid #ffc0c0;
background-color: #ffffff;
}
.text-tags-__1-49 {
color: #4d4d4d;
font-size: 14px;
letter-spacing: 1.25px;
line-height: 24px;
text-align: left;
text-transform: capitalize;
text-decoration: none;
font-family: Roboto;
font-weight: 500;
text-wrap: nowrap;
}
.simple-chip__1-43 {
padding-top: 0px;
padding-right: 8px;
padding-bottom: 0px;
padding-left: 8px;
display: flex;
flex-direction: row;
justify-content: center;
flex-wrap: nowrap;
align-items: center;
gap: 8px;
box-sizing: border-box;
border-radius: 16px;
border: 1px solid #c0caff;
background-color: #ffc0c0;
}
.text-tag-1__1-44 {
color: #4d4d4d;
font-size: 14px;
letter-spacing: 1.25px;
line-height: 24px;
text-align: left;
text-transform: capitalize;
text-decoration: none;
font-family: Roboto;
font-weight: 500;
text-wrap: nowrap;
}
.simple-chip__1-45 {
padding-top: 0px;
padding-right: 8px;
padding-bottom: 0px;
padding-left: 8px;
display: flex;
flex-direction: row;
justify-content: center;
flex-wrap: nowrap;
align-items: center;
gap: 8px;
box-sizing: border-box;
border-radius: 16px;
border: 1px solid #c0caff;
background-color: #ffc0c0;
}
.text-tag-2__1-46 {
color: #4d4d4d;
font-size: 14px;
letter-spacing: 1.25px;
line-height: 24px;
text-align: left;
text-transform: capitalize;
text-decoration: none;
font-family: Roboto;
font-weight: 500;
text-wrap: nowrap;
}
.simple-chip__1-47 {
padding-top: 0px;
padding-right: 8px;
padding-bottom: 0px;
padding-left: 8px;
display: flex;
flex-direction: row;
justify-content: center;
flex-wrap: nowrap;
align-items: center;
gap: 8px;
box-sizing: border-box;
border-radius: 16px;
border: 1px solid #c0caff;
background-color: #ffc0c0;
}
.text-tag-3__1-48 {
color: #4d4d4d;
font-size: 14px;
letter-spacing: 1.25px;
line-height: 24px;
text-align: left;
text-transform: capitalize;
text-decoration: none;
font-family: Roboto;
font-weight: 500;
text-wrap: nowrap;
}
.text-info__1-51 {
padding-top: 8px;
padding-right: 8px;
padding-bottom: 8px;
padding-left: 8px;
display: flex;
flex-direction: column;
justify-content: flex-start;
flex-wrap: nowrap;
align-items: flex-start;
gap: 8px;
box-sizing: border-box;
flex-grow: 1;
display: flex;
width: 100%;
border-radius: 4px;
border: 1px solid #c0caff;
background-color: #ffffff;
}
.text-header__1-52 {
color: #4d4d4d;
font-size: 14px;
letter-spacing: 1.25px;
line-height: 20px;
text-align: left;
text-transform: capitalize;
text-decoration: none;
font-family: Roboto;
font-weight: 500;
text-wrap: wrap;
flex-grow: 1;
display: flex;
width: 100%;
}
.text-desc__1-60 {
color: #4d4d4d;
font-size: 12px;
letter-spacing: 1.25px;
line-height: 12px;
text-align: left;
text-decoration: none;
font-family: Roboto;
font-weight: 500;
text-wrap: wrap;
flex-grow: 1;
display: flex;
width: 100%;
}
The rendered result looks like this:
Example #2 - Export a component with variants or building your design system
In the next case, our designer has created a new component that should be used across all our projects, so it should become a part of our design system library.
Here is our component:
Our component has 6 variants and 3 properties:
IsRemovable that can be 'true' or 'false'
Shape that can be 'Round', 'Square', or 'Semi'
Text that is bonded to the label value
Let's see how Figmular exports our Angular components for this frame:
Html TypeScript CSS
Copy // simple-chip.component.html
<div
class="root_base"
[ngClass]="{
root_Shape_is_Round: Shape === 'Round',
root_Shape_is_Square: Shape === 'Square',
root_Shape_is_Semi: Shape === 'Semi'
}"
>
<span class="chip_base">{{Text}}</span>
<div *ngIf="isRemovable === 'true'" class="union_isRemovable_is_true">
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M8 16C12.4183 16 16 12.4183 16 8C16 3.58172 12.4183 0 8 0C3.58172 0 0 3.58172 0 8C0 12.4183 3.58172 16 8 16Z"
fill="#D9D9D9"
/>
<path
d="M5.23344 11.6889L8.11454 8.58222L11 11.6975L11.7337 11.018L8.79649 7.84687L11.7334 4.67999L11.0002 4L8.11501 7.1111L5.23365 4.00023L4.5 4.67976L7.43306 7.84645L4.50021 11.0089L5.23344 11.6889Z"
fill="#4D4D4D"
/>
</svg>
</div>
</div>/
Copy // simple-chip.component.ts
import { Component, Input } from "@angular/core";
@Component({
selector: "app-simple-chip",
templateUrl: "./simple-chip.component.html",
styleUrls: ["./simple-chip.component.scss"],
})
export class SimpleChipComponent {
@Input() isRemovable: "false" | "true" = "false";
@Input() Text = "Chip";
@Input() Shape: "Round" | "Square" | "Semi" = "Round";
}
Copy // simple-chip.component.scss
.root_Shape_is_Round {
border-radius: 16px;
}
.root_Shape_is_Square {
border-radius: 0px;
}
.root_Shape_is_Semi {
border-radius: 8px;
}
.root_base {
padding-top: 0px;
padding-right: 8px;
padding-bottom: 0px;
padding-left: 8px;
display: flex;
box-sizing: border-box;
border: 1px solid #c0caff;
background-color: #ffc0c0;
}
.chip_base {
color: #4d4d4d;
font-size: 14px;
letter-spacing: 1.25px;
line-height: 24px;
text-align: left;
text-transform: capitalize;
text-decoration: none;
font-family: Roboto;
font-weight: 500;
text-wrap: nowrap;
}
.union_Shape_is_Round {
display: flex;
}
.union_Shape_is_Square {
display: flex;
}
.union_Shape_is_Semi {
display: flex;
}
.union_isRemovable_is_true {
display: flex;
}
In the result we can see that:
Figmular used conditions to change the layout based on the input parameters
The TypeScript file contains correct input fields and their possible values
SVG icon has been exported in the process
Now you can just copy those files into your project, or into your design system library and start using the SimpleChipComponent .
Example #3 - Export a Frame with Components
In this example, we will use an updated frame from Example #1 - Export a simple Frame where the plain chips are replaced with instances of our new component Simple Chip with different properties:
As developers, we would like to export this frame to a new Angular component, so we need to have the Simple Chip component exported as well. Let's generate Angular code for this frame using Figmular and see what we get:
Html TypeScript CSS
Copy // notifications-with-components.component.html
<div class="notifications-with-components_4-74">
<div class="tags-panel_4-75">
<span class="text-tags-_4-76">Tags:</span>
<app-simple-chip
[text]="'Tag 1'"
[isRemovable]="false"
[shape]="'Round'"
></app-simple-chip>
<app-simple-chip
[text]="'Tag 2'"
[isRemovable]="false"
[shape]="'Square'"
></app-simple-chip>
<app-simple-chip
[text]="'Tag 3'"
[isRemovable]="true"
[shape]="'Semi'"
></app-simple-chip>
</div>
<div class="text-info_4-83">
<span class="text-header_4-84">Header</span>
<span class="text-desc_4-85"
>Long description for this block. This text should be wrapped to fit info
the width</span
>
</div>
</div>
Copy // notifications-with-components.component.ts
import { Component, Input } from "@angular/core";
@Component({
selector: "app-notifications-with-components",
templateUrl: "./notifications-with-components.component.html",
styleUrls: ["./notifications-with-components.component.scss"],
})
export class NotificationsWithComponentsComponent {}
Copy // notifications-with-components.component.scss
.notifications-with-components_4-74 {
padding: 8px;
display: flex;
flex-direction: column;
justify-content: flex-start;
flex-wrap: nowrap;
align-items: flex-start;
gap: 4px;
box-sizing: border-box;
border-color: #c0caff;
border-style: solid;
border-width: 1px;
background: #ffffff;
}
.tags-panel_4-75 {
padding: 8px;
display: flex;
flex-direction: row;
justify-content: flex-start;
flex-wrap: nowrap;
align-items: flex-start;
gap: 16px;
box-sizing: border-box;
border-radius: 4px;
border-color: #ffc0c0;
border-style: solid;
border-width: 1px;
background: #ffffff;
width: -webkit-fill-available;
}
.text-tags-_4-76 {
color: #4d4d4d;
font-size: 14px;
font-family: Roboto;
line-height: 24px;
letter-spacing: 1.25px;
text-transform: capitalize;
text-decoration: none;
font-weight: 500;
text-align: left;
text-wrap: nowrap;
}
.text-info_4-83 {
padding: 8px;
display: flex;
flex-direction: column;
justify-content: flex-start;
flex-wrap: nowrap;
align-items: flex-start;
gap: 8px;
box-sizing: border-box;
border-radius: 4px;
border-color: #c0caff;
border-style: solid;
border-width: 1px;
background: #ffffff;
width: -webkit-fill-available;
}
.text-header_4-84 {
color: #4d4d4d;
font-size: 14px;
font-family: Roboto;
line-height: 20px;
letter-spacing: 1.25px;
text-transform: capitalize;
text-decoration: none;
font-weight: 500;
text-align: left;
text-wrap: wrap;
width: -webkit-fill-available;
}
.text-desc_4-85 {
color: #4d4d4d;
font-size: 12px;
font-family: Roboto;
line-height: 12px;
letter-spacing: 1.25px;
text-decoration: none;
font-weight: 500;
text-align: left;
text-wrap: wrap;
width: -webkit-fill-available;
}
First, we see a new dropdown below the code export section. This dropdown shows all the components involved in the current export operation:
That means that SimpleChipComponent is exported as a part of the package as well. And we can see its usage in the frame's component like this:
Copy // Usage of SimpleChipComponent component in NotificationsWithComponentsComponent
<app-simple-chip
[Text]="'Tag 1'"
[isRemovable]="'false'"
[Shape]="'Round'"
></app-simple-chip>
Here is the final result rendered in CodeSandbox:
Summary