APIPASS · 2025
A new design system
Translating APIPASS's identity into a modern, scalable system — and redesigning the platform's core surfaces on top of it.
- Role
- Research, design system, UI redesign
- Company
- APIPASS — iPaaS · Integration platform
- Focus
- Design system, UI redesign, Research
The platform's layout had become outdated. After aligning stakeholder expectations with customer feedback, I began researching how to translate APIPASS's existing identity into a new, more modern and more effective design system.
The documented system
Documentation
One library, documented end to end
The system is documented so anyone — designer, engineer or PM — can find a component, understand which tokens it consumes, and use it without asking.
62
Components
99
Design tokens
120+
Icons
10
Text styles
4
Elevations
Principles
Four rules the library never breaks
Token-driven
Nothing is hard-coded. Colour, type, spacing and elevation all resolve through named tokens.
Semantic by intent
Consumers reference roles like Text/Primary or Danger/Surface — never raw hex — so themes and tweaks stay global.
Accessible by default
Text/Primary on Surface/Default clears WCAG AA; status colours are paired with legible text tones.
One source of truth
The same tokens power Figma variables and the CSS custom properties devs ship.
Token architecture
Three tiers, one source of truth
Primitives hold the raw values. Semantic roles alias them. Components consume the roles. Change a primitive once and it lands everywhere downstream.
Tier 1
Primitives
Raw, context-free values — the full palette plus spacing, radius and stroke scales. Named for what they ARE.
Tier 2
Semantic
Roles that alias a primitive. Named for what they're FOR. This is the layer you consume.
Tier 3
Component
Components bind to semantic tokens. The Alert's fill, border and text are all roles — never hex.
Tier 1 · Primitives
Colour primitives
The raw palette — 52 values named for what they are, never for where they are used.
Neutral
White
#FFFFFF
50
#F5F5F5
75
#F2F2F8
100
#E6E6E6
200
#D9D9D9
300
#C1C1CD
400
#B3B3B3
500
#757575
600
#5A5A5A
700
#2C2C2C
800
#1E1E1E
900
#121619
Brand · Indigo
500
#546193
700
#3F4D82
900
#222D57
Red · Danger
50
#FEE9E7
100
#FDD3D0
200
#FCB3AD
500
#EC221F
700
#C00F0C
900
#900B09
Green · Positive
50
#EBFFEE
100
#CFF7D3
200
#AFF4C6
400
#14AE5C
500
#009951
900
#02542D
Amber · Warning
50
#FFF1C2
100
#FFE8A3
500
#E5A000
600
#E8B931
800
#682D03
900
#401B01
Violet · Accent
500
#8A38F5
Tier 2 · Semantic
Colour roles
Every role points at a primitive. Consumers reference the role, so re-theming is a single edit at the alias layer.
Text
- Text/PrimaryNeutral/800
- Text/SecondaryNeutral/500
- Text/DisabledNeutral/400
- Text/On BrandNeutral/White
- Text/LinkBrand/700
Surface
- Surface/PageNeutral/50
- Surface/DefaultNeutral/White
- Surface/SubtleNeutral/75
- Surface/InverseNeutral/800
Border
- Border/SubtleNeutral/100
- Border/DefaultNeutral/200
- Border/StrongNeutral/400
Interactive
- Brand/DefaultBrand/900
- Brand/HoverBrand/700
- Brand/MutedBrand/500
- Accent/DefaultViolet/500
Danger
- Danger/DefaultRed/500
- Danger/HoverRed/700
- Danger/TextRed/900
- Danger/SurfaceRed/50
- Danger/BorderRed/200
Positive
- Positive/DefaultGreen/500
- Positive/TextGreen/900
- Positive/SurfaceGreen/50
- Positive/BorderGreen/200
Warning
- Warning/DefaultAmber/500
- Warning/TextAmber/900
- Warning/SurfaceAmber/50
- Warning/BorderAmber/100
Typography
Inter, ten registered styles
One family across the product. Every style is a registered token — no ad-hoc size or weight in a design file.
Display
Inter Bold · 72 / 120% / -3%
API-PASS
Title
Inter Regular · 32 / 120% / 0
Design system
Heading
Inter Semi Bold · 24 / 120% / -2%
Component library & tokens
Subtitle
Inter Regular · 20 / 120% / 0
Roles that map to primitives
Body
Inter Regular · 16 / 140% / 0
The quick brown fox jumps over the lazy dog. 0123456789
Body Strong
Inter Semi Bold · 16 / 140% / 0
Emphasis within body copy
Body Tight
Inter Regular · 16 / 100% / 0
Dense UI text at 100% line-height
Label
Inter Semi Bold · 16 / 100% / 0
BUTTON LABEL
Small
Inter Regular · 14 / 140% / 0
Secondary and helper text
Small Strong
Inter Semi Bold · 14 / 140% / 0
Table headers & eyebrows
Measurement
Spacing, radius and stroke
An 8-point spacing scale, seven radii and two stroke weights. Anything off the scale is a bug, not a decision.
Spacing
- Space/44
- Space/88
- Space/1212
- Space/1616
- Space/2424
- Space/3232
- Space/4848
- Space/6464
Radius
- Radius/none0
- Radius/xs2
- Radius/sm4
- Radius/md8
- Radius/lg24
- Radius/xl32
- Radius/pillfull
Stroke
- Stroke/hairline · 1px
- Stroke/thick · 2px
Icons: Ionicons, 24px box, 1.5px stroke, 120+ glyphs.
Elevation
Four levels, one meaning each
Shadows carry hierarchy, not decoration: controls lift 1px, cards float, modals detach, pressed states sink.
Elevation/1 · Control
y1 · blur3 · spread1 · 15%
Elevation/2 · Card
layered y4 + y16 · 5% + 10%
Elevation/3 · Modal
y4 · blur16 · 16%
Elevation/Pressed
y1 · blur2 · 30%
Iconography
Ionicons · outline · 24px
The system uses the Ionicons outline set on a 24×24 canvas. 120+ glyphs are in use; a representative sample is shown below. Icons inherit colour from the text token beside them.
Component index
62 variant sets, grouped by intent
Components are catalogued by the job they do, with the number of published variants beside each family.
Actions & inputs
- Primary button×12
- Secondary button×6
- Split button×2
- Switch×4
- Action Button×3
- Input field×17
- Dropdown×5
- Checkbox×6
- Radio button×4
- Filter Chip×2
- Search Field
Navigation
- Side Menu×2
- Top Menu×5
- Menu lateral×2
- Menu lateral · Item×6
- Menu · Expandir×4
- Navigation pill×2
- Sub header pills×4
- Tabs selection×6
- Header Tab×2
- Display option×2
- Breadcrumb
- Connector Menu Item×3
Data display
- Table v2×17
- Query · Row×2
- Query · Card×2
- Config · Field label×2
- Status Dot×5
- Chip · Status×5
- SDS · KeyValue Row×3
- Icon Tile×5
- Chart type select×8
- Chart displays×8
Feedback & overlays
- Alert×8
- Dialog×4
- Forms / modal×4
- Tooltip×4
- Accordion×2
- Loader×5
- Loader animado×10
- Toast
- Canvas · Toast×2
Tags & badges
- Tag · Brand set×20
- Tag · Scheme set×12
- Tag · Chave-valor
- Tag · Contador
- Status Dot×5
Flow & canvas (product)
- Flow Node×3
- Flow card×2
- Port×2
- Preview · Header×3
- Canvas · Tile×5
- Canvas · Nó×3
- Canvas · Chip filtro×2
- Canvas · Porta×3
- Bloco de expressão×4
- Expressão · Limiar×4
Typography components
- Text Content Heading×2
- Text Content Title×2
- Text Link List×2
- Text List×2
Deep dives
How each family binds to tokens
For the families engineers touch most, the documentation spells out exactly which token drives which property.
Buttons
Primary and secondary actions, shown as live instances. Sizes: normal & large. States: default, hover, disabled.
- FillBrand/Default → Brand/Hover on hover
- LabelText/On Brand · style Label
- RadiusRadius/Control (8)
- PaddingSpace/12 × Space/24 (normal) · Space/16 × Space/32 (large)
- DisabledSurface Neutral/300 · Text/Disabled
- ElevationElevation/1 · Control
- SecondarySurface/Default · Border/Strong · Text/Primary
Tags
The clearest expression of the semantic colour system: five schemes, each in a solid (Primary) and soft (Secondary) treatment.
- Primary fill{Scheme}/Default (e.g. Danger/Default)
- Primary textText/On Brand
- Secondary fill{Scheme}/Surface (e.g. Danger/Surface)
- Secondary text{Scheme}/Text (e.g. Danger/Text)
- Secondary border{Scheme}/Border
- RadiusRadius/Pill (9999)
- Neutral schemeNeutral/700 · Neutral/100 · Text/Secondary
Alerts
Inline messages in neutral and danger tones, with optional icon, action and arrow.
- Neutral surfaceSurface/Subtle · Border/Default
- Danger surfaceDanger/Surface · Danger/Border
- Danger textDanger/Text
- IconIonicons 24 · inherits text tone
- RadiusRadius/Card (8)
- PaddingSpace/12–16
- ActionText/Link or Danger/Text
Input fields
A 17-variant family covering text, textarea, states and validation.
- SurfaceSurface/Default
- BorderBorder/Default → Brand/Muted on focus
- TextText/Primary · placeholder Text/Disabled
- Labelstyle Small Strong · Text/Primary
- ErrorDanger/Border · Danger/Text
- RadiusRadius/Control (8)
- PaddingSpace/12
Dropdown / Select
The select control across its states — closed, open, with selection.
- TriggerSurface/Default · Border/Default
- FocusBorder → Brand/Muted
- MenuSurface/Default · Elevation/2 · Card
- Option hoverSurface/Subtle
- SelectedBrand/Muted tint · Text/Primary
- RadiusRadius/Control (8)
Navigation
The chrome that frames the product: primary top bar, collapsible side menu, and the pills and tabs used for in-page navigation.
- Bar surfaceSurface/Default · Border/Default
- Active itemBrand/Default · Text/On Brand
- Idle itemText/Secondary
- HoverSurface/Subtle
- Pill selectedBrand/Muted · Radius/Pill
- Tab underlineBrand/Default 2px
Table v2
The data table and its row states — header, default, hover, expanded, selected — specified at 1440, 1280 and 1024.
- HeaderSurface/Subtle · Text/Secondary · style Small Strong
- RowSurface/Default · Body
- DividerBorder/Subtle (1px)
- Hover rowSurface/Subtle
- SelectedBrand/Muted tint
- Status cellChip/Status → Positive/Danger/Warning tokens
Live specimens
Buttons and tags, rendered from the tokens
The flagship families are documented as live instances, not screenshots — every fill, border and label below resolves to the tokens above.
Buttons
Primary · normal
default
hover
disabled
with icon
Secondary
default
hover
large
Tags
Five schemes, each in a solid (Primary) and soft (Secondary) treatment.
- BrandTag ×Tag ×
- PositiveTag ×Tag ×
- DangerTag ×Tag ×
- WarningTag ×Tag ×
- NeutralTag ×Tag ×
Handoff
Figma → tokens.json → CSS
The handoff is mechanical on purpose: variables export to tokens.json, tokens.json becomes custom properties, and components consume var(--token). No one retypes a hex code.
1
Figma Variables
source of truth
2
Export
Tokens Studio / REST API
3
tokens.json + CSS
--custom-properties
4
App consumes
var(--token)
Token mapping
- Color/Brand/900--color-brand-900#222d57
- Brand/Default--brand-defaultvar(--color-brand-900)
- Danger/Surface--danger-surfacevar(--color-red-50)
- Space/16--space-1616px
- Radius/md--radius-md8px
Generated CSS
/* Tier 1 — primitives */
:root {
--color-brand-900: #222d57;
--color-red-50: #fee9e7;
/* Tier 2 — semantic (alias primitives) */
--brand-default: var(--color-brand-900);
--danger-surface: var(--color-red-50);
--radius-control: 8px;
}
.btn-primary {
background: var(--brand-default);
border-radius: var(--radius-control);
color: var(--text-on-brand);
}Do
- Reference semantic tokens (Brand/Default) — never raw hex or a primitive directly
- Apply the registered text styles instead of manual size/weight
- Stay on the scale: Space/* and Radius/* only
- Bind variables so a single edit propagates everywhere
- Redline in token names — “padding: Space/16”, not “16px”
Don't
- Hardcode values like #222d57 or 8px
- Invent one-off values (gap 10, radius 5) — extend the scale instead
- Detach an instance to restyle it
- Mix Roboto into an Inter system
- Duplicate a component to fake a new variant
Audit
Known drift
A mature library accumulates inconsistencies. Rather than silently fixing them, the audit documents each one with a recommendation and a severity, so the team can decide and act deliberately.
| Issue | What we found | Recommendation | Severity |
|---|---|---|---|
| Stray Roboto | ~13 text nodes use Roboto inside an Inter system | Re-point to Inter / the text styles | Medium |
| Material defaults | Leftover MD3 purples (#9747ff, #fef7ff, #79747e) & Roboto from annotation components | Strip annotation artifacts from shipping components | Medium |
| Duplicate sets | Two Query/Row, duplicated Canvas/* sets, two Tag sets (20 & 12) | Consolidate to one source per component | Medium |
| Off-grid spacing | gap 10 and padding 11 break the 4-pt grid | Snap to Space/8 or Space/12 | Low |
| Rogue radii | 5px and 23px appear alongside the scale | Snap to Radius/sm (4) and Radius/lg (24) | Low |
| Pill radius | Both 100 and 9999 used for fully-round | Standardise on Radius/pill | Low |
| Icon stroke | 1.6px leaks from Ionicons defaults (57×) | Accept as icon-intrinsic or normalise to 1.5 | Low |
| Generic names | “Component 1”, “Model8” obscure intent | Rename semantically (Alert, etc.) | Low |
Try it
Interactive states
The same tokens, wired up: hover, focus, press and select these controls to see the states the system specifies.
Buttons
Hover and hold to see Brand/Hover and the pressed elevation.
Tags
Click a tag to toggle between the solid and soft treatment.
Selected: Brand
Input & dropdown
Focus the field for Brand/Muted focus ring; open the select for Elevation/2.
Table rows
Hover for Surface/Subtle; click to select with the Brand/Muted tint.
The takeaway
The system isn't a folder of screens — it's a token graph with a UI on top. Edit the token, and the documentation updates with the product.
- 52 primitives
- 33 semantic tokens
- 10 text styles
- 4 elevations
- 62 components
- 120+ icons
Spec rules
Rules that hold it together
- 01One component, many variants — variation lives in properties, never in a duplicated frame.
- 02Four breakpoints, one collapse order: 1440, 1280, 1024, 768.
- 03Status is always colour plus text, never colour alone.
- 04Every value comes from a token — no loose hex codes, spacings or radii in a spec.
- 05Every state is drawn: default, hover, active, disabled, loading, error and empty.
- 06Copy is written in the spec, not left to implementation.
Deliverables
Handed to engineering, ready to build
All the tokens, components and variables were handed off for the engineering team to build the company's new interface.
01
Tokens
99 variables across colour, type, spacing, radius and elevation — exported as tokens.json and CSS custom properties.
02
Components
62 variant sets published with every state drawn, so engineers build from the spec instead of guessing.
03
Documentation
A living document generated from the file itself: usage rules, token mapping, do / don't and the audit trail.