@onflow/kit
π§ This library is currently in alpha and is subject to change.
@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β
useCurrentFlowUser
β Authenticate and manage the current Flow useruseFlowAccount
β Fetch Flow account details by addressuseFlowBlock
β Query latest or specific Flow blocksuseFlowConfig
β Access the current Flow configurationuseFlowEvents
β Subscribe to Flow events in real-timeuseFlowQuery
β Execute Cadence scripts with optional argumentsuseFlowMutate
β Send transactions to the Flow blockchainuseFlowTransaction
β Track transaction status updates
Installationβ
_10npm 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.
_24import React from "react"_24import App from "./App"_24import { FlowProvider } from "@onflow/kit"_24import flowJSON from "../flow.json"_24_24function 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_24export default Root
If you're using [Next.js], put this in layout.tsx
. Adapt as appropriate for other frontend frameworks.
Hooksβ
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
β
_10import { useCurrentFlowUser } from "@onflow/kit"
Returns:β
user: CurrentUser
β The current user object from FCLauthenticate: () => Promise<CurrentUser>
β Triggers wallet authenticationunauthenticate: () => void
β Logs the user out
_16function 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
β
_10import { useFlowAccount } from "@onflow/kit"
Parameters:β
address?: string
β Flow address (with or without0x
prefix)query?: UseQueryOptions<Account | null, Error>
β Optional TanStackQuery options
Returns: UseQueryResult<Account | null, Error>
β
_19function AccountDetails() {_19 const { data: account, isLoading, error, refetch } = useFlowAccount({_19 address: "0x1cf0e2f2f715450",_19 query: { staleTime: 5000 },_19 })_19_19 if (isLoading) return <p>Loading account...</p>_19 if (error) return <p>Error fetching account: {error.message}</p>_19 if (!account) return <p>No account data</p>_19_19 return (_19 <div>_19 <h2>Account: {account.address}</h2>_19 <p>Balance: {account.balance}</p>_19 <pre>{account.code}</pre>_19 <button onClick={refetch}>Refetch</button>_19 </div>_19 )_19}
useFlowBlock
β
_10import { useFlowBlock } from "@onflow/kit"
Parameters:β
sealed?: boolean
β Iftrue
, fetch latest sealed blockid?: string
β Block by IDheight?: number
β Block by heightquery?: UseQueryOptions<Block | null, Error>
β Optional TanStackQuery options
Only one of sealed
, id
, or height
should be provided.
Returns: UseQueryResult<Block | null, Error>
β
_14function LatestBlock() {_14 const { data: block, isLoading, error } = useFlowBlock({ query: { staleTime: 10000 } })_14_14 if (isLoading) return <p>Loading...</p>_14 if (error) return <p>Error: {error.message}</p>_14 if (!block) return <p>No block data.</p>_14_14 return (_14 <div>_14 <h2>Block {block.height}</h2>_14 <p>ID: {block.id}</p>_14 </div>_14 )_14}
useFlowConfig
β
_10import { useFlowConfig } from "@onflow/kit"
Returns: FlowConfig
β
_10function 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
β
_10import { useFlowEvents } from "@onflow/kit"
Parameters:β
startBlockId?: string
β Optional ID of the block to start listening fromstartHeight?: number
β Optional block height to start listening fromeventTypes?: string[]
β Array of event type strings (e.g.,A.0xDeaDBeef.Contract.EventName
)addresses?: string[]
β Filter by Flow addressescontracts?: string[]
β Filter by contract identifiersopts?: { heartbeatInterval?: number }
β Options for subscription heartbeatonEvent: (event: Event) => void
β Callback for each event receivedonError?: (error: Error) => void
β Optional error handler
Example:β
_10function 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
β
_10import { useFlowQuery } from "@onflow/kit"
Parameters:β
cadence: string
β Cadence script to runargs?: (arg, t) => unknown[]
β Function returning FCL argumentsquery?: UseQueryOptions<unknown, Error>
β Optional TanStackQuery options
Returns: UseQueryResult<unknown, Error>
β
_22function 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
β
_10import { useFlowMutate } from "@onflow/kit"
Parameters:β
mutation?: UseMutationOptions<string, Error, FCLMutateParams>
β Optional TanStackQuery mutation options
Returns: UseMutationResult<string, Error, FCLMutateParams>
β
_33function CreatePage() {_33 const { mutate, isPending, error, data: txId } = useFlowMutate({_33 mutation: {_33 onSuccess: (txId) => console.log("TX ID:", txId),_33 },_33 })_33_33 const sendTransaction = () => {_33 mutate({_33 cadence: `transaction() {_33 prepare(acct: &Account) {_33 log(acct.address)_33 }_33 }`,_33 args: (arg, t) => [],_33 proposer: fcl.currentUser,_33 payer: fcl.currentUser,_33 authorizations: [],_33 limit: 100,_33 })_33 }_33_33 return (_33 <div>_33 <button onClick={sendTransaction} disabled={isPending}>_33 Send Transaction_33 </button>_33 {isPending && <p>Sending transaction...</p>}_33 {error && <p>Error: {error.message}</p>}_33 {txId && <p>Transaction ID: {txId}</p>}_33 </div>_33 )_33}
useFlowTransaction
β
_10import { useFlowTransaction } from "@onflow/kit"
Parameters:β
id: string
β Transaction ID to subscribe to
Returns:β
transactionStatus: TransactionStatus | null
error: Error | null
_12function TransactionComponent() {_12 const txId = "your-transaction-id-here"_12 const { transactionStatus, error } = useFlowTransaction({ id: txId })_12_12 if (error) return <div>Error: {error.message}</div>_12_12 return (_12 <div>_12 Status: {transactionStatus?.statusString}_12 </div>_12 )_12}