Skip to content

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 data from target when clicked, and send the transaction ID 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 {
  chainId: string;
  method: "eth_sendTransaction";
  attribution?: boolean;
  params: EthSendTransactionParams;
}
type EthSendTransactionParams {
  abi: Abi | [];
  to: Hex;
  value?: string;
  data?: Hex;
}

Transaction Success

If the transaction 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.

route.tsx
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",
        }),
      ],
    };
  }
});