A fast, typed React 19 hooks library for the Figma Variables API: fetch, update, and manage design tokens via the official Figma REST API.
Built for the modern web, this library provides a suite of hooks to fetch, manage, and mutate your design tokens, making it easy to sync them between Figma and your React applications, Storybooks, or design system dashboards.
- β
Token Agnostic for the Best DX: Our library doesn't care how you get your Figma token. Use environment variables,
localStorage, a state management library, or even a simple input field. This framework-agnostic approach means it works seamlessly with Vite, Next.js, Create React App, and more, without locking you into a specific build tool. - βοΈ Modern React Hooks: A full suite of hooks for fetching and mutating Figma variables, collections, and modes.
- βοΈ Ergonomic Mutations: A
useMutation-style API for creating, updating, and deleting variables, providing clear loading and error states. - π TypeScript-first: Strictly typed for an ergonomic and safe developer experience. Get autocompletion for all API responses.
- π Storybook & Next.js Ready: Perfect for building live design token dashboards or style guides.
- π Local JSON Support: Use local JSON files exported from Figma Dev Mode plugins when you don't have a Figma Enterprise account, enabling offline development and static deployments.
- π§ Style Dictionary Integration: Coming soon in future beta releases - seamless integration with Amazon's Style Dictionary for multi-platform design token distribution.
- β 100% Test Coverage - Comprehensive test suite with 78 tests covering all hooks, utilities, and edge cases via Vitest
- β Consistent Error Handling - Standardized error propagation with clear messages from the Figma API
- β Strictly Typed APIs - Modern TypeScript best practices with full type inference and autocompletion
- β Predictable Hook Signatures - Consistent, composable patterns designed for safe React integrations
- β Developer-First Architecture - Clean folder structure, path aliases, and logical component separation
- β React Ecosystem - Built specifically for React apps, Storybook, Next.js, and design system dashboards
- β Ergonomic DX - Intuitive API that's easy to use in both prototype and production environments
- β Minimal Dependencies - Leverages SWR for caching with careful dependency selection for optimal bundle size
npm install @figma-vars/hooks
# or
yarn add @figma-vars/hooks
# or
pnpm add @figma-vars/hooksPeer dependencies: You'll need
reactandreact-dom.
The library is designed to be as flexible as possible. You provide the Figma token and file key, and the hooks handle the rest.
Wrap your application (or the relevant component tree) with the FigmaVarsProvider. This makes the Figma token and file key available to all the hooks.
// src/main.tsx or App.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import { FigmaVarsProvider } from '@figma-vars/hooks'
import App from './App'
// The token can come from anywhere: .env, localStorage, state, etc.
const FIGMA_TOKEN = import.meta.env.VITE_FIGMA_TOKEN
const FIGMA_FILE_KEY = 'your-figma-file-key'
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<FigmaVarsProvider
token={FIGMA_TOKEN}
fileKey={FIGMA_FILE_KEY}>
<App />
</FigmaVarsProvider>
</React.StrictMode>
)Now, you can use the query hooks anywhere in your app:
// src/components/TokenList.tsx
import { useVariables } from '@figma-vars/hooks'
export function TokenList() {
const { data, isLoading, error } = useVariables()
if (isLoading) return <div>Loading tokens...</div>
if (error) return <div>Error: {error.message}</div>
// The 'data' object contains variables, collections, and modes
const variables = Object.values(data?.variables ?? {})
return (
<ul>
{variables.map(variable => (
<li key={variable.id}>
{variable.name}: {JSON.stringify(variable.valuesByMode)}
</li>
))}
</ul>
)
}To create, update, or delete variables, use the provided mutation hooks. They follow a standard pattern, returning a mutate function and states for data, isLoading, and error.
Here's an example of creating a new variable:
// src/components/CreateVariableForm.tsx
import { useCreateVariable } from '@figma-vars/hooks'
import type { CreateVariablePayload } from '@figma-vars/hooks'
function CreateVariableForm({ collectionId }: { collectionId: string }) {
const { mutate, data, isLoading, error } = useCreateVariable()
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault()
const form = event.currentTarget
const variableName = (form.elements.namedItem('variableName') as HTMLInputElement)?.value
if (!variableName) return
const payload: CreateVariablePayload = {
name: variableName,
variableCollectionId: collectionId,
resolvedType: 'COLOR', // Example type
}
mutate(payload)
}
return (
<form onSubmit={handleSubmit}>
<input
name='variableName'
placeholder='New variable name'
/>
<button
type='submit'
disabled={isLoading}>
{isLoading ? 'Creating...' : 'Create Variable'}
</button>
{error && <p>Error: {error.message}</p>}
{data && <p>Created variable with ID: {data.id}</p>}
</form>
)
}If you don't have a Figma Enterprise account (required for the Variables API), you can still use this library with local JSON files exported from Figma Dev Mode plugins. This is perfect for:
- Offline Development: Work on your design system without an internet connection
- Static Deployments: Deploy design token dashboards to static hosting
- CI/CD Pipelines: Use exported JSON files in automated workflows
- Team Collaboration: Share design tokens without API access
We recommend using the Variables Exporter for Dev Mode plugin:
- Install the plugin in Figma
- Open your Figma file in Dev Mode
- Run the plugin and export your variables as JSON
- Save the JSON file to your project (e.g.,
src/assets/figma-variables.json)
This plugin exports the exact same format that the Figma Variables API returns, ensuring perfect compatibility with this library.
// src/main.tsx or App.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import { FigmaVarsProvider } from '@figma-vars/hooks'
import App from './App'
import variablesData from './assets/figma-variables.json'
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<FigmaVarsProvider
token={null} // No token needed when using fallbackFile
fileKey={null} // No fileKey needed when using fallbackFile
fallbackFile={variablesData}>
<App />
</FigmaVarsProvider>
</React.StrictMode>
)You can also pass the JSON as a string if you prefer:
import variablesJson from './assets/figma-variables.json?raw'
;<FigmaVarsProvider
token={null}
fileKey={null}
fallbackFile={variablesJson}>
<App />
</FigmaVarsProvider>When using the Figma API, it's essential to keep your Personal Access Token (PAT) secure. Here are some best practices:
- Never hardcode your PAT in your code.
- Use environment variables or a secure storage mechanism to store your PAT.
- Limit the scope of your PAT to only the necessary permissions.
- Rotate your PAT regularly.
For advanced use cases, you can use the useFigmaToken hook to access the token and file key from the context.
// src/components/AdvancedUsage.tsx
import { useFigmaToken } from '@figma-vars/hooks'
function AdvancedUsage() {
const { token, fileKey } = useFigmaToken()
// Use the token and file key to make custom API requests
const apiRequest = async () => {
const response = await fetch(`https://api.figma.com/v1/files/${fileKey}/variables`, {
headers: {
'X-Figma-Token': token,
},
})
const data = await response.json()
console.log(data)
}
return <button onClick={apiRequest}>Make API Request</button>
}All hooks return an error state that you can use to handle errors.
// src/components/ErrorHandling.tsx
import { useVariables } from '@figma-vars/hooks'
function ErrorHandling() {
const { data, isLoading, error } = useVariables()
if (error) {
return (
<div>
<h2>Error</h2>
<p>{error.message}</p>
</div>
)
}
// Render data or loading state
}Understanding the difference between local and published variables is important for building robust design systems:
- Developing and iterating on design tokens within a single file
- Testing changes before publishing them to a library
- Working offline with exported JSON files from Figma Dev Mode
- Building file-specific dashboards or tools
- You need to modify variables using mutation hooks (create, update, delete)
- Consuming variables from a published Figma library
- Building design system dashboards that track the source of truth
- Monitoring consistency across files that consume the same library
- Validating that local variables match published tokens
- You only need read access to stable, shared design tokens
Key Difference: Local variables are file-specific and can be modified, while published variables are library tokens shared across multiple files and represent the canonical source of truth for your design system.
The Figma API has rate limits to ensure fair usage. When using useVariables() or usePublishedVariables(), keep these considerations in mind:
- Default limits: Figma enforces rate limits on API requests (typically 1000 requests per minute per token)
- SWR caching: This library uses SWR for intelligent caching and revalidation, which helps minimize unnecessary API calls
- Published variables: These are typically more stable than local variables, so they can be cached longer without risk of stale data
- Best practices:
- Use the
revalidateOnFocus: falseoption in production if you don't need real-time updates - Consider longer
dedupingIntervalvalues for published variables (they change less frequently) - Leverage the
fallbackFileoption for static deployments to avoid API calls entirely - Monitor your API usage in the Figma API console if you're building high-traffic applications
- Use the
Example with custom SWR config:
import { SWRConfig } from 'swr'
import { FigmaVarsProvider } from '@figma-vars/hooks'
function App() {
return (
<SWRConfig
value={{
revalidateOnFocus: false,
dedupingInterval: 60000, // 1 minute
}}>
<FigmaVarsProvider
token={FIGMA_TOKEN}
fileKey={FIGMA_FILE_KEY}>
<YourComponents />
</FigmaVarsProvider>
</SWRConfig>
)
}useVariables(): Fetches all local variables for the file key provided to theFigmaVarsProvider. Returns a SWR hook state withdata,isLoading, anderrorproperties. The actual Figma response is indata.data. WhenfallbackFileis provided, it uses the local JSON data instead of making an API request.usePublishedVariables(): Fetches published variables from a Figma library. Published variables represent the source of truth for design tokens in a design system and are shared across files. Use this hook when accessing tokens consumed from a library rather than local file variables.useVariableCollections(): A convenience hook that returns just the variable collections from the mainuseVariablesdata.useVariableModes(): A convenience hook that returns just the variable modes from the mainuseVariablesdata.useFigmaToken(): A simple hook to access the token and file key from the context.
The FigmaVarsProvider accepts the following props:
token: Figma Personal Access Token (PAT) for API authentication. Can benullwhen usingfallbackFile.fileKey: Figma file key for the target file. Required for API requests but can benullwhen usingfallbackFile.fallbackFile: Optional local JSON file (as object or string) to use instead of API requests. Perfect for users without Figma Enterprise accounts.
All mutation hooks return an object with the following shape: { mutate, data, isLoading, error }.
useCreateVariable(): Creates a new variable. Themutatefunction expects aCreateVariablePayloadobject.useUpdateVariable(): Updates an existing variable. Themutatefunction expects an object{ variableId, payload }wherepayloadis anUpdateVariablePayload.useDeleteVariable(): Deletes a variable. Themutatefunction expects thevariableId(string) of the variable to delete.useBulkUpdateVariables(): Creates, updates, or deletes multiple entities in a single batch operation. Themutatefunction expects aBulkUpdatePayloadobject.
All types are exported from @figma-vars/hooks. The core response type from Figma for local variables is LocalVariablesResponse.
The provider model makes integration trivial. Simply wrap your Storybook stories or Next.js pages with the FigmaVarsProvider.
// In a Storybook story
import { FigmaVarsProvider, useVariables } from '@figma-vars/hooks'
export const TokensStory = () => (
<FigmaVarsProvider
token='YOUR_TOKEN'
fileKey='YOUR_FILE_KEY'>
<TokenList />
</FigmaVarsProvider>
)
const TokenList = () => {
const { data } = useVariables()
return <pre>{JSON.stringify(data?.variables, null, 2)}</pre>
}PRs and issues are welcome! Please see CONTRIBUTING.md for guidelines.
This project is licensed under the MIT License. Β© 2024β2025 Mark Learst
