Button
In order to render buttons you should use our <Button>
component, button()
helper or plain objects. Frames.js supports the following button types:
Post Button
import { Button, button } from "frames.js/core";
<Button action="post">Click me</Button>;
button({ action: "post", label: "Click me" });
// plain object
{
action: "post",
label: "Click me",
}
This button sends a request to a URL on which it was rendered. If you want to navigate to different route in your app, you can use target
prop which should be set to relative path.
<Button action="post" target="/next-route">
Click me
</Button>;
button({ action: "post", target: "/next-route", label: "Click me" });
// plain object
{
action: "post",
target: "/next-route",
label: "Click me",
}
The target
path will be resolved relatively to current URL.
Passing state between frames
<Button
action="post"
target={{ query: { foo: "bar" }, pathname: "/next-route" }}
>
Click me
</Button>;
button({
action: "post",
target: { query: { foo: "bar" }, pathname: "/next-route" },
label: "Click me",
});
// plain object
{
action: "post",
target: { query: { foo: "bar" }, pathname: "/next-route" },
label: "Click me",
}
The state will be available in the frame handler via ctx.searchParams
e.g.
ctx.searchParams.foo; // bar
Post Redirect Button
Post redirect button is a special kind of post
button that when users clicks the button, first a message is sent to frames handler and then it is expected that handler will redirect the user to a different route using redirect
call.
It accepts same props as post
button.
import { Button, button } from "frames.js/core";
<Button
action="post_redirect"
target={{ query: { foo: "bar" }, pathname: "/next-route" }}
>
Click me
</Button>;
button({
action: "post_redirect",
target: { query: { foo: "bar" }, pathname: "/next-route" },
label: "Click me",
});
// plain object
{
action: "post_redirect",
target: { query: { foo: "bar" }, pathname: "/next-route" },
label: "Click me",
}
Link Button
Link button navigates to external URL when clicked.
import { Button, button } from "frames.js/core";
<Button action="link" target="https://google.com">
Click me
</Button>;
button({ action: "link", target: "https://google.com", label: "Click me" });
// plain object
{
action: "link",
target: "https://google.com",
label: "Click me",
}
Mint Button
Mint button creates a new token when clicked.
import { Button, button } from "frames.js/core";
import { getTokenUrl } from "frames.js";
<Button
action="mint"
target={getTokenUrl({
address: "0x8f5ed2503b71e8492badd21d5aaef75d65ac0042",
chain: zora,
tokenId: "3",
})}
>
Mint
</Button>;
button({
action: "mint",
target: getTokenUrl({
address: "0x8f5ed2503b71e8492badd21d5aaef75d65ac0042",
chain: zora,
tokenId: "3",
}),
label: "Mint",
});
// plain object
{
action: "mint",
target: getTokenUrl({
address: "0x8f5ed2503b71e8492badd21d5aaef75d65ac0042",
chain: zora,
tokenId: "3",
}),
label: "Mint",
}
Tx Button
Tx button requests transaction or signature data from target
when clicked, and sends the transaction ID or signature to the frame's post_url
or the button's post_url
if it is set.
import { Button, button } from "frames.js/core";
<Button action="tx" target="/txdata" post_url="/tx-success">
Buy storage
</Button>;
button({
action: "tx",
target: "/txdata",
post_url: "/tx-success",
label: "Buy storage",
});
// plain object
{
action: "tx",
target: "/txdata",
post_url: "/tx-success",
label: "Buy storage",
}
Transaction data
The endpoint specified in target
should return a JSON object with the following structure:
type TransactionTargetResponse =
| TransactionTargetResponseSendTransaction
| TransactionTargetResponseSignTypedDataV4;
type EthSendTransactionParams = {
/** JSON ABI. This must include the encoded function type and should include any potential error types. */
abi: JSON | Abi | [];
/** transaction to address */
to: Address;
/** value of ether to send with the transaction in wei */
value?: string;
/** optional transaction call data */
data?: Hex;
};
type TransactionTargetResponseSendTransaction = {
/** A [CAIP-2](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-2.md) chain ID to identify the tx network e.g. 'eip155:1' for Ethereum mainnet */
chainId: string;
method: "eth_sendTransaction";
/** Specific parameters for chainId and method */
params: EthSendTransactionParams;
/** Return false to omit the [calldata attribution](https://www.notion.so/warpcast/Frame-Transactions-Public-9d9f9f4f527249519a41bd8d16165f73#c1c3182208ce4ae4a7ffa72129b9795a) suffix. If this value is undefined or true, clients will append the attribution suffix. */
attribution?: boolean;
};
type EthSignTypedDataV4Params = {
domain: {
chainId?: number;
name?: string;
salt?: Hex;
verifyingContract?: Address;
version?: string;
};
types: TypedData;
primaryType: string;
message: Record<string, unknown>;
};
type TransactionTargetResponseSignTypedDataV4 = {
/** A [CAIP-2](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-2.md) chain ID to identify the tx network e.g. 'eip155:1' for Ethereum mainnet */
chainId: string;
method: "eth_signTypedData_v4";
/** Specific parameters for chainId and method */
params: EthSignTypedDataV4Params;
};
Transaction Success
If the transaction or signing is successful, the frame will send a POST request to the URL specified in post_url
or the frame post_url
. This can be handled by the frame to show a success message or redirect the user to a different page.
import { Button } from "frames.js/next";
import { createFrames } from "frames.js/next";
const export frames = createFrames()
export const GET = frames(async (ctx) => {
return {
image: (
<div tw="flex">
Execute transaction
</div>
),
buttons: [
<Button action="tx" target="/txdata" post_url="/tx-success">
Execute
</Button>,
// or using button helper
button({
action: "tx",
target: "/txdata",
post_url: "/tx-success",
label: "Execute",
}),
],
};
})
// /tx-success/route.tsx
import { frames } from ../route.tsx";
const handleRequest = frames(async (ctx) => {
if (message?.transactionId) {
return {
image: (
<div tw="flex">
Transaction submitted! {ctx.message.transactionId}
</div>
),
buttons: [
<Button
action="link"
target={`https://www.onceupon.gg/tx/${ctx.message.transactionId}`}
>
View on block explorer
</Button>,
// or using button helper
button({
action: "link",
target: `https://www.onceupon.gg/tx/${ctx.message.transactionId}`,
label: "View on block explorer",
}),
],
};
}
});