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.
β 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/hooks
Peer dependencies: You'll need
react
andreact-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>
)
}
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
}
useVariables()
: Fetches all local variables for the file key provided to theFigmaVarsProvider
. Returns a SWR hook state withdata
,isLoading
, anderror
properties. The actual Figma response is indata.data
.useVariableCollections()
: A convenience hook that returns just the variable collections from the mainuseVariables
data.useVariableModes()
: A convenience hook that returns just the variable modes from the mainuseVariables
data.useFigmaToken()
: A simple hook to access the token and file key from the context.
All mutation hooks return an object with the following shape: { mutate, data, isLoading, error }
.
useCreateVariable()
: Creates a new variable. Themutate
function expects aCreateVariablePayload
object.useUpdateVariable()
: Updates an existing variable. Themutate
function expects an object{ variableId, payload }
wherepayload
is anUpdateVariablePayload
.useDeleteVariable()
: Deletes a variable. Themutate
function expects thevariableId
(string) of the variable to delete.useBulkUpdateVariables()
: Creates, updates, or deletes multiple entities in a single batch operation. Themutate
function expects aBulkUpdatePayload
object.
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