Skip to main content

@onflow/kit

warning

🚧 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​

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], put this in layout.tsx. Adapt as appropriate for other frontend frameworks.


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>​


_19
function 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​


_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>​


_14
function 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​


_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>​


_33
function 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​


_10
import { useFlowTransaction } from "@onflow/kit"

Parameters:​

  • id: string – Transaction ID to subscribe to

Returns:​

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

_12
function 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
}