Repository navigation
⚠️ Breaking Changes
Styling: UnoCSS → Tailwind CSS v4
@thinkbuff/figma-theme/unocssis removed. The theme now ships Tailwind v4 CSS (@thinkbuff/figma-theme/css/*) generated from the Figma tokens;@thinkbuff/figma-theme/colorsis unchanged.@thinkbuff/figma-reactshipsstyles.css, so consumers only need:@import 'tailwindcss'; @import '@thinkbuff/figma-react/styles.css';
- Utilities follow the theme's utility contract (
text-figma-sm,rounded-figma-sm,bg-figma-*, …). Dark mode is.figma-dark; FigJam is.figjam. - Components use inline SVG icons, so no icon preset is needed.
Button API rework
variant+colorcollapsed into a singlevariant:primary,secondary,destructive,secondary-destructive,inverse,success,figjam,link,link-danger,ghost.size="wide"replacesfullWidth; newiconslot prop.
| Before | After |
|---|---|
variant="solid" color="primary" (default) |
variant="primary" |
variant="solid" color="danger" |
variant="destructive" |
variant="solid" color="success" |
variant="success" |
variant="solid" color="inverse" |
variant="inverse" |
variant="outline" / color="secondary" |
variant="secondary" |
variant="outline" color="danger" |
variant="secondary-destructive" |
variant="link" color="danger" |
variant="link-danger" |
variant="link" |
variant="link" |
variant="ghost" |
variant="ghost" |
fullWidth |
size="wide" |
ActionIconSplit added
- New compound component for the UI3
Button icon splitset (41x24 small / 49x32 large):ActionIconSplitroot plusButton(primary action) andChevron(16px trigger half) subparts. Each half supportsrender,aria-expandedfills follow the dialog-toggle spec.
ActionIcon / Toggle API rework
ActionIcon:activeAppearanceremoved (the on state now always follows the UI3 dialog-toggle spec); newvariant="secondary"for the strokedButton iconvariant.Toggle:strokereplaced byvariant—'highlighted'(default, previous fill behavior),'default'(icon-swap only, no pressed fill),'secondary'(the formerstrokelook with thebordertranslucenttoken).
Menu items: UI3 tokens + ItemSwitch
DropdownMenu.ItemSwitchandContextMenu.ItemSwitchadded: amenuitemcheckboxrow with a Switch cell on the leading side (the spec'sMenu row/Toggle). Clicking the row toggles the switch; the menu stays open.- Menu row highlight now uses
bg-menu-selected(wasbg-selected-strong— visibly wrong in FigJam dark).ItemBadgeusesbg-toolbar+text-onbrand;ItemCheckrenders the spec's plain 16px check icon instead of a filled chip. Disabled items unify ontext-menu-disabled/icon-menu-disabled.
Fields: UI3 variants and states
Select.Trigger: newstrokeprop (Stroke=Falserenders borderless onbg-default); focus and open states are a singleborder-selectedswap (the extra outline ring is removed); the open value shows the spec'stexthighlightblock; theiconlead is a flush 24px cell, and onsize="large"a 32px cell holding the spec's 24pxbg-secondarywell.VariableChipis 16px tall (was 18px) and usesborder-disabledwhen disabled.- New
VariableCell: the spec'sVariable Cell— a 24px bordered row with the variable icon cell plus a label. ValueField.NumericSelect: the dropdown segment usesbg-selected+border-selectedwhile open (the spec's selected-chevron state).
Slider and Swatch: UI3 spec variants
Slider: newmodifiedprop renders the spec'sStroke (Modified)thumb (bg-defaultknob,icon-onbrandring, elevation-300). Hue/opacity thumbs now embed the spec's 12px_Chit 24square instead of a 6px disc. Disabled thumb usesbg-disabled(wasbg-disabled-secondary); the track and gradient-chit rings use thebordertranslucenttoken (were hardcoded); stepper ticks useicon-tertiary/icon(wereblack/30/black/85).Swatch: newtype="opacity"(left half solid, right half at ~24% alpha — the spec'sType=Opacity) andshape="circle"(the spec's 16px round chit). The inset ring now usesbordertranslucent(same values as the previous hardcoded hexes — no visual change).
Avatar and Badge: UI3 spec variants
Avatar: initials fills now bind to themultiplayer*/textonmultiplayer*tokens (were hardcoded light-theme hexes — dark themes were visibly wrong). Colors renamed to spec names (magenta→pink,slate→grey); newoverflow-unread/overflow-readcolors for "+N" avatars; newdisabledprop (bg-tertiary+text);shape="square"usesrounded-figma-smatsize="small"(spec r=2).Badge:size="small"(14px) removed — no such badge in the spec;size="large"added (16px with 13px text — the spec's "Badge large"). Newvariant="alt"for the "Badge small alt" subtle-fill family (default/count/count-inactive/strong); new colorsfigjam,menu,merged,archived; thewarningstrong fill usesicon-warningper spec. NewBadgeDot(the spec's "Badge Dot": 9pxbg-defaultpill + 5pxbg-branddot).
Radio, Tabs, Toast, Visual Bell, ScrollArea: UI3 tokens and states
Radiobutton variant: default border now usesbordertranslucent(was opaqueborder).Tabs: trigger gains the spec'sborder-selectedfocus ring; unselected hover usesbg-hover(same values, correct token).Toast: surface usesbg-menu/text-menutokens (same values); shadow upgraded to the spec's "LEGACY - HUD shadow" via newshadow-figma-hudutility.VisualBell:color="default"is now the spec's light bell (bg-default+text+ elevation-100) — replaces the dark#2c2c2chardcoded fill. Action/dismiss edges usebordertranslucent; hover/active use the secondary-button transparent tokens.ScrollArea: thumb uses thescrollbartoken via newbg-figma-scrollbarutility (wastext-secondary).
Remaining UI3 audit items
Switch:indeterminaterenders the spec'sicon.16.mixedglyph (16px,icon-onbrand;icon-disabledwhen disabled) instead of a hand-drawn bar.Input/Textarea: disabled state follows the spec per size —size="default"keepsbg-default+border-defaultstroke;size="large"staysbg-secondarywith no stroke.- Disabled colors aligned to the spec's tokens where values are identical:
text-tertiaryonSelect,ToggleGroupitems and labels, and all ValueField elements;border-defaulton ValueField outlines. LinkTooltip.Action: newstrongprop for the spec'sbody.medium.strongCTA weight (w550).Separator: documented per-surface divider tokens — menu/tooltip surfaces should passbg-figma-border-menu/bg-figma-border-tooltip.AlertDialogstory CTA gap aligned to the Modal footer's 8px rhythm.
Tokens: generated from packages/theme/tokens/
@thinkbuff/figma-theme/colorsno longer exportsBaseThemeCSSVariables/BaseThemeCSSVariableKey— each mode map is complete on its own.- New exports:
FigJamDarkThemeCSSVariables,DevModeLightThemeCSSVariables,DevModeDarkThemeCSSVariables,SlidesLightThemeCSSVariables,SlidesDarkThemeCSSVariables(+ types). - Token values are now generated from
packages/theme/tokens/viapnpm tokens:import; the FigJam block no longer claims:root(that selector is Figma light only).
Primitives: Radix UI → Base UI (@base-ui/react)
asChild→rendereverywhere (e.g.<Dialog.Trigger render={<Button />} />). UsenativeButton={false}when rendering a non-button element throughButton.- Change callbacks receive a second
eventDetailsargument (onValueChange,onCheckedChange,onPressedChange,onOpenChange). Dismissal is cancelled viaeventDetails.cancel()instead ofevent.preventDefault()ononPointerDownOutside/onEscapeKeyDown/onInteractOutside(removed). - State attributes follow Base UI:
data-checked,data-unchecked,data-pressed,data-active,data-popup-open,data-highlighted,data-starting-style/data-ending-style. Open triggers are styled througharia-expanded. - Overlays (
Popover,Tooltip,DropdownMenu,Select) position through a Base UI Positioner:avoidCollisionsandupdatePositionStrategyare removed,collisionPaddingdefaults to 5, andsideOffsetmeasures to the popup edge (no automatic arrow height). Checkbox:checked="indeterminate"→indeterminateprop.ToggleGroup:type="single" | "multiple"→multiple;value/defaultValueare always arrays.Slider:onValueCommit→onValueCommitted;minStepsBetweenThumbs→minStepsBetweenValues;invertedremoved;SliderRootwraps a Base UIControl.ScrollArea:type/scrollHideDelayremoved; the scrollbar shows while hovering or scrolling.Tabs:activationMode→activateOnFocus(defaultfalse: arrow keys move focus without selecting);forceMount→keepMounted; disabled tabs stay focusable.Tooltip:delayDuration→delay,skipDelayDuration→timeout,disableHoverableContent→disableHoverablePopup;delay/closeDelaylive on the trigger.DropdownMenu:Item onSelect→onClick;Labelmust be insideGroup/RadioGroup; checkbox and radio items keep the menu open.Select: passitemstoRootso the trigger shows labels;position→alignItemWithTrigger;Item asChildremoved; the empty value isnull;Labelmust be insideGroup; focus returns to the trigger on close.Dialog/AlertDialog/Sheet:Overlayrenders Base UIBackdrop;AlertDialog.ActionandAlertDialog.Cancelboth close the dialog.Labelis a native<label>.react/react-dompeer range is now^19: components forwardrefas a prop, which React 18 cannot pass to function components. Node>=24.21.0.
Theme tokens: UI3 sync
- Spacing renumbered to the UI3 scale:
--figma-space-5is now 32px (was 20px),--figma-space-6is now 40px (was 28px), and--figma-space-7is removed. Utilities such asp-figma-5/gap-figma-6follow the new values.
Components: UI3 look
- Components are restyled to Figma's UI3 against the official UI3 Design file and its exported variables. Layouts may shift:
Input,Selecttriggers,TabsandToggleGroupitems are 24px tall (were 32px),CheckboxandRadioare 16px, andSwitchis 32×16. - Solid buttons have no hover background; focus is a 1px outline plus a 1px ring. Fields are outline-only on
bg-secondary. Menus, popovers and dialogs use 13px radius and elevation shadows; menu highlight isbg-menu-selected. ActionIconopen state (aria-expanded) is now subtle (bg-selected) instead of solid brand.- Inline
RadioGroupitems are 20px apart (were 8px).
Per-component details, behavior notes and QA checklists live in docs/migration/.
🚀 Features
- UI3 semantic typography utilities:
text-figma-body-{small,medium,large}andtext-figma-heading-{small,medium,large}set size, leading and tracking in one class; theheading-*variants also applyfont-weight: 550. Matchingleading-figma-*andtracking-figma-*utilities are available. - UI3 elevation shadows:
shadow-figma-elevation-{100..500}plus semanticshadow-figma-tooltip/shadow-figma-menu/shadow-figma-modal(elevation 300/400/500). Elevations are theme-scoped, so.figma-darkgets the dark values (inset highlights) even on nested elements;shadow-figma-slideris unchanged.
🧹 Chore
- Toolchain moved to Vite+ (
vp check/vp test/vp pack), Oxlint and Oxfmt, pnpm catalogs, Storybook 10. - Added Vitest unit, browser-mode behavior and visual regression tests.