Skip to main content

@onflow/kit

@onflow/kit is a lightweight React utility library that simplifies interacting with the Flow blockchain. It provides a collection of hooks, similar to those in other popular web3 libraries, that make it easier to build frontends that understand blockchain interactions. In the future, it will also provide components designed to make authentication, script execution, transactions, event subscriptions, and network configuration seamless in React apps.

πŸ”Œ Included React Hooks​

Installation​


_10
npm install @onflow/kit

Usage​

Wrapping Your App With FlowProvider​

Begin by wrapping your application with the FlowProvider to initialize FCL configuration. This sets up FCL and maps its configuration keys to a strictly typed format for your hooks.


_24
import React from 'react';
_24
import App from './App';
_24
import { FlowProvider } from '@onflow/kit';
_24
import flowJSON from '../flow.json';
_24
_24
function Root() {
_24
return (
_24
<FlowProvider
_24
config={{
_24
accessNodeUrl: 'https://access-mainnet.onflow.org',
_24
flowNetwork: 'mainnet',
_24
appDetailTitle: 'My On Chain App',
_24
appDetailIcon: 'https://example.com/icon.png',
_24
appDetailDescription: 'A decentralized app on Flow',
_24
appDetailUrl: 'https://myonchainapp.com',
_24
}}
_24
flowJson={flowJSON}
_24
>
_24
<App />
_24
</FlowProvider>
_24
);
_24
}
_24
_24
export default Root;

If you're using Next.js, place the FlowProvider inside your layout.tsx. Since React hooks must run on the client, you may need to wrap the provider in a separate file that begins with 'use client' to avoid issues with server-side rendering. Adjust this setup as needed for other frontend frameworks.

πŸ‘‰ Learn more about configuring flow.json in the Configuration Guide.


Hooks​

info

Many of these hooks are built using @tanstack/react-query, which provides powerful caching, revalidation, and background refetching features. As a result, you’ll see return types like UseQueryResult and UseMutationResult throughout this section. Other typesβ€”such as Account, Block, and CurrentUserβ€”are from the Flow Client Library (FCL) TypeDefs. Refer to their respective documentation for full type definitions and usage patterns.

useCurrentFlowUser​


_10
import { useCurrentFlowUser } from '@onflow/kit';

Returns:​

  • user: CurrentUser – The current user object from FCL
  • authenticate: () => Promise<CurrentUser> – Triggers wallet authentication
  • unauthenticate: () => void – Logs the user out

_16
function AuthComponent() {
_16
const { user, authenticate, unauthenticate } = useCurrentFlowUser();
_16
_16
return (
_16
<div>
_16
{user.loggedIn ? (
_16
<>
_16
<p>Logged in as {user.addr}</p>
_16
<button onClick={unauthenticate}>Logout</button>
_16
</>
_16
) : (
_16
<button onClick={authenticate}>Login</button>
_16
)}
_16
</div>
_16
);
_16
}


useFlowAccount​


_10
import { useFlowAccount } from '@onflow/kit';

Parameters:​

  • address?: string – Flow address (with or without 0x prefix)
  • query?: UseQueryOptions<Account | null, Error> – Optional TanStackQuery options

Returns: UseQueryResult<Account | null, Error>​


_24
function AccountDetails() {
_24
const {
_24
data: account,
_24
isLoading,
_24
error,
_24
refetch,
_24
} = useFlowAccount({
_24
address: '0x1cf0e2f2f715450',
_24
query: { staleTime: 5000 },
_24
});
_24
_24
if (isLoading) return <p>Loading account...</p>;
_24
if (error) return <p>Error fetching account: {error.message}</p>;
_24
if (!account) return <p>No account data</p>;
_24
_24
return (
_24
<div>
_24
<h2>Account: {account.address}</h2>
_24
<p>Balance: {account.balance}</p>
_24
<pre>{account.code}</pre>
_24
<button onClick={refetch}>Refetch</button>
_24
</div>
_24
);
_24
}


useFlowBlock​


_10
import { useFlowBlock } from '@onflow/kit';

Parameters:​

  • sealed?: boolean – If true, fetch latest sealed block
  • id?: string – Block by ID
  • height?: number – Block by height
  • query?: UseQueryOptions<Block | null, Error> – Optional TanStackQuery options

Only one of sealed, id, or height should be provided.

Returns: UseQueryResult<Block | null, Error>​


_18
function LatestBlock() {
_18
const {
_18
data: block,
_18
isLoading,
_18
error,
_18
} = useFlowBlock({ query: { staleTime: 10000 } });
_18
_18
if (isLoading) return <p>Loading...</p>;
_18
if (error) return <p>Error: {error.message}</p>;
_18
if (!block) return <p>No block data.</p>;
_18
_18
return (
_18
<div>
_18
<h2>Block {block.height}</h2>
_18
<p>ID: {block.id}</p>
_18
</div>
_18
);
_18
}


useFlowConfig​


_10
import { useFlowConfig } from '@onflow/kit';

Returns: FlowConfig​


_10
function MyComponent() {
_10
const config = useFlowConfig();
_10
_10
return (
_10
<div>
_10
<p>Current network: {config.flowNetwork}</p>
_10
<p>Current access node: {config.accessNodeUrl}</p>
_10
</div>
_10
);
_10
}


useFlowEvents​


_10
import { useFlowEvents } from '@onflow/kit';

Parameters:​

  • startBlockId?: string – Optional ID of the block to start listening from
  • startHeight?: number – Optional block height to start listening from
  • eventTypes?: string[] – Array of event type strings (e.g., A.0xDeaDBeef.Contract.EventName)
  • addresses?: string[] – Filter by Flow addresses
  • contracts?: string[] – Filter by contract identifiers
  • opts?: { heartbeatInterval?: number } – Options for subscription heartbeat
  • onEvent: (event: Event) => void – Callback for each event received
  • onError?: (error: Error) => void – Optional error handler

Example:​


_10
function EventListener() {
_10
useFlowEvents({
_10
eventTypes: ['A.0xDeaDBeef.SomeContract.SomeEvent'],
_10
onEvent: (event) => console.log('New event:', event),
_10
onError: (error) => console.error('Error:', error),
_10
});
_10
_10
return <div>Listening for events...</div>;
_10
}


useFlowQuery​


_10
import { useFlowQuery } from '@onflow/kit';

Parameters:​

  • cadence: string – Cadence script to run
  • args?: (arg, t) => unknown[] – Function returning FCL arguments
  • query?: UseQueryOptions<unknown, Error> – Optional TanStackQuery options

Returns: UseQueryResult<unknown, Error>​


_22
function QueryExample() {
_22
const { data, isLoading, error, refetch } = useFlowQuery({
_22
cadence: `
_22
access(all)
_22
fun main(a: Int, b: Int): Int {
_22
return a + b
_22
}
_22
`,
_22
args: (arg, t) => [arg(1, t.Int), arg(2, t.Int)],
_22
query: { staleTime: 10000 },
_22
});
_22
_22
if (isLoading) return <p>Loading query...</p>;
_22
if (error) return <p>Error: {error.message}</p>;
_22
_22
return (
_22
<div>
_22
<p>Result: {data}</p>
_22
<button onClick={refetch}>Refetch</button>
_22
</div>
_22
);
_22
}


useFlowMutate​


_10
import { useFlowMutate } from '@onflow/kit';

Parameters:​

  • mutation?: UseMutationOptions<string, Error, FCLMutateParams> – Optional TanStackQuery mutation options

Returns: UseMutationResult<string, Error, FCLMutateParams>​


_38
function CreatePage() {
_38
const {
_38
mutate,
_38
isPending,
_38
error,
_38
data: txId,
_38
} = useFlowMutate({
_38
mutation: {
_38
onSuccess: (txId) => console.log('TX ID:', txId),
_38
},
_38
});
_38
_38
const sendTransaction = () => {
_38
mutate({
_38
cadence: `transaction() {
_38
prepare(acct: &Account) {
_38
log(acct.address)
_38
}
_38
}`,
_38
args: (arg, t) => [],
_38
proposer: fcl.currentUser,
_38
payer: fcl.currentUser,
_38
authorizations: [],
_38
limit: 100,
_38
});
_38
};
_38
_38
return (
_38
<div>
_38
<button onClick={sendTransaction} disabled={isPending}>
_38
Send Transaction
_38
</button>
_38
{isPending && <p>Sending transaction...</p>}
_38
{error && <p>Error: {error.message}</p>}
_38
{txId && <p>Transaction ID: {txId}</p>}
_38
</div>
_38
);
_38
}


useFlowRevertibleRandom​


_10
import { useFlowRevertibleRandom } from '@onflow/kit';

Parameters:​

  • min?: string – Minimum random value (inclusive), as a UInt256 decimal string. Defaults to "0".
  • max: string – Maximum random value (inclusive), as a UInt256 decimal string. Required.
  • count?: number – Number of random values to fetch (must be at least 1). Defaults to 1.
  • query?: Omit<UseQueryOptions<any, Error>, "queryKey" | "queryFn"> – Optional TanStack Query settings like staleTime, enabled, retry, etc.

Returns: UseQueryResult<RevertibleRandomResult[], Error>​

Each RevertibleRandomResult includes:

  • blockHeight: string β€” The block height from which the random value was generated.
  • value: string β€” The random UInt256 value, returned as a decimal string.

_31
function RandomValues() {
_31
const {
_31
data: randoms,
_31
isLoading,
_31
error,
_31
refetch,
_31
} = useFlowRevertibleRandom({
_31
min: '0',
_31
max: '1000000000000000000000000', // Example large max
_31
count: 3,
_31
query: { staleTime: 10000 },
_31
});
_31
_31
if (isLoading) return <p>Loading random numbers...</p>;
_31
if (error) return <p>Error fetching random numbers: {error.message}</p>;
_31
if (!randoms) return <p>No random values generated.</p>;
_31
_31
return (
_31
<div>
_31
<h2>Generated Random Numbers</h2>
_31
<ul>
_31
{randoms.map((rand, idx) => (
_31
<li key={idx}>
_31
Block {rand.blockHeight}: {rand.value}
_31
</li>
_31
))}
_31
</ul>
_31
<button onClick={refetch}>Regenerate</button>
_31
</div>
_31
);
_31
}

Notes:​

  • Randomness is generated using the on-chain revertibleRandom function on Flow, producing pseudorandom values tied to block and script execution.
  • Values are deterministic: The values returned for identical calls within the same block will be identical.
  • If count is larger than one, the returned values are distinct.
  • This hook is designed for simple use cases that don't require unpredictability, such as randomized UIs. Since the hook uses script executions on existing blocks, the random source is already public and the randoms are predictable.
  • For more advanced use cases that do require on-chain randomness logic via transactions, Flow provides built-in support using Cadence's revertibleRandom and commit-reveal scheme.

useFlowTransactionStatus​


_10
import { useFlowTransactionStatus } from '@onflow/kit';

Parameters:​

  • id: string – Transaction ID to subscribe to

Returns:​

  • transactionStatus: TransactionStatus | null
  • error: Error | null

_10
function TransactionComponent() {
_10
const txId = 'your-transaction-id-here';
_10
const { transactionStatus, error } = useFlowTransactionStatus({ id: txId });
_10
_10
if (error) return <div>Error: {error.message}</div>;
_10
_10
return <div>Status: {transactionStatus?.statusString}</div>;
_10
}


useCrossVmTokenBalance​


_10
import { useFlowQuery } from '@onflow/kit';

Fetch the balance of a token balance for a given user across both Cadence and EVM environments.

Parameters:​

  • owner: string – Cadence address of the account whose token balances you want.
  • vaultIdentifier?: string – Optional Cadence resource identifier (e.g. "0x1cf0e2f2f715450.FlowToken.Vault") for on-chain balance
  • erc20AddressHexArg?: string – Optional bridged ERC-20 contract address (hex) for EVM/COA balance
  • query?: Omit<UseQueryOptions<unknown, Error>, "queryKey" | "queryFn"> – Optional TanStack Query config (e.g. staleTime, enabled)

Note: You must pass owner, and one of vaultIdentifier or erc20AddressHexArg.

Returns: UseQueryResult<UseCrossVmTokenBalanceData | null, Error>​

Where UseCrossVmTokenBalanceData is defined as:


_10
interface UseCrossVmTokenBalanceData {
_10
cadence: TokenBalance // Token balance of Cadence vault
_10
evm: TokenBalance // Token balance of EVM (COA stored in /storage/coa)
_10
combined: TokenBalance // Combined balance of both Cadence and EVM
_10
}

Where TokenBalance is defined as:


_10
interface TokenBalance {
_10
value: bigint // Balance value in smallest unit
_10
formatted: string // Formatted balance string (e.g. "123.45")
_10
precision: number // Number of decimal places for the token
_10
}


_21
function QueryExample() {
_21
const { data, isLoading, error, refetch } = useCrossVmTokenBalance({
_21
owner: '0x1cf0e2f2f715450',
_21
vaultIdentifier: '0x1cf0e2f2f715450.FlowToken.Vault',
_21
erc20AddressHexArg: '0x1234567890abcdef1234567890abcdef12345678', // Optional
_21
query: { staleTime: 10000 },
_21
});
_21
_21
if (isLoading) return <p>Loading token balance...</p>;
_21
if (error) return <p>Error fetching token balance: {error.message}</p>;
_21
_21
return (
_21
<div>
_21
<h2>Token Balances</h2>
_21
<p>Cadence Balance: {data.cadence.formatted} (Value: {data.cadence.value})</p>
_21
<p>EVM Balance: {data.evm.formatted} (Value: {data.evm.value})</p>
_21
<p>Combined Balance: {data.combined.formatted} (Value: {data.combined.value})</p>
_21
<button onClick={refetch}>Refetch</button>
_21
</div>
_21
);
_21
}