diff --git a/.changeset/dirty-breads-swim.md b/.changeset/dirty-breads-swim.md
new file mode 100644
index 00000000000..baa9089ef79
--- /dev/null
+++ b/.changeset/dirty-breads-swim.md
@@ -0,0 +1,5 @@
+---
+"thirdweb": patch
+---
+
+Add `amountEditable` and `tokenEditable` props on `BuyWidget` component to disable token selection and token amount editing
diff --git a/apps/dashboard/src/app/bridge/buy-widget/BuyWidgetEmbed.client.tsx b/apps/dashboard/src/app/bridge/buy-widget/BuyWidgetEmbed.client.tsx
index d22d738d950..13aea46b57c 100644
--- a/apps/dashboard/src/app/bridge/buy-widget/BuyWidgetEmbed.client.tsx
+++ b/apps/dashboard/src/app/bridge/buy-widget/BuyWidgetEmbed.client.tsx
@@ -20,6 +20,8 @@ export function BuyWidgetEmbed({
buttonLabel,
receiverAddress,
country,
+ amountEditable,
+ tokenEditable,
}: {
chainId?: number;
tokenAddress?: Address;
@@ -34,6 +36,8 @@ export function BuyWidgetEmbed({
buttonLabel?: string;
receiverAddress?: Address;
country?: string;
+ amountEditable?: boolean;
+ tokenEditable?: boolean;
}) {
const client = useMemo(
() =>
@@ -68,6 +72,8 @@ export function BuyWidgetEmbed({
buttonLabel={buttonLabel}
receiverAddress={receiverAddress}
country={country}
+ amountEditable={amountEditable}
+ tokenEditable={tokenEditable}
onSuccess={() => {
sendMessageToParent({
source: "buy-widget",
diff --git a/apps/dashboard/src/app/bridge/buy-widget/page.tsx b/apps/dashboard/src/app/bridge/buy-widget/page.tsx
index 0942e58802a..0e9d9c56471 100644
--- a/apps/dashboard/src/app/bridge/buy-widget/page.tsx
+++ b/apps/dashboard/src/app/bridge/buy-widget/page.tsx
@@ -73,6 +73,14 @@ export default async function Page(props: {
const receiverAddress = parseQueryParams(searchParams.receiver, onlyAddress);
const country = parseQueryParams(searchParams.country, (v) => v);
+ // Editable params
+ const amountEditable = parseQueryParams(searchParams.amountEditable, (v) =>
+ v === "false" ? false : undefined,
+ );
+ const tokenEditable = parseQueryParams(searchParams.tokenEditable, (v) =>
+ v === "false" ? false : undefined,
+ );
+
return (
@@ -90,6 +98,8 @@ export default async function Page(props: {
buttonLabel={buttonLabel}
receiverAddress={receiverAddress}
country={country}
+ amountEditable={amountEditable}
+ tokenEditable={tokenEditable}
/>
diff --git a/apps/playground-web/src/app/bridge/buy-widget/BuyPlayground.tsx b/apps/playground-web/src/app/bridge/buy-widget/BuyPlayground.tsx
index a068b4d2959..caba667077b 100644
--- a/apps/playground-web/src/app/bridge/buy-widget/BuyPlayground.tsx
+++ b/apps/playground-web/src/app/bridge/buy-widget/BuyPlayground.tsx
@@ -24,6 +24,8 @@ const defaultOptions: BridgeComponentsPlaygroundOptions = {
transactionData: "",
currency: "USD",
showThirdwebBranding: true,
+ amountEditable: true,
+ tokenEditable: true,
},
theme: {
darkColorOverrides: {},
diff --git a/apps/playground-web/src/app/bridge/checkout-widget/CheckoutPlayground.tsx b/apps/playground-web/src/app/bridge/checkout-widget/CheckoutPlayground.tsx
index f6b2b2ee7c6..f2ade2e172a 100644
--- a/apps/playground-web/src/app/bridge/checkout-widget/CheckoutPlayground.tsx
+++ b/apps/playground-web/src/app/bridge/checkout-widget/CheckoutPlayground.tsx
@@ -24,6 +24,8 @@ const defaultOptions: BridgeComponentsPlaygroundOptions = {
receiverAddress: undefined,
currency: "USD",
showThirdwebBranding: true,
+ amountEditable: true,
+ tokenEditable: true,
},
theme: {
darkColorOverrides: {},
diff --git a/apps/playground-web/src/app/bridge/components/CodeGen.tsx b/apps/playground-web/src/app/bridge/components/CodeGen.tsx
index d364dc4599e..51b44b68c46 100644
--- a/apps/playground-web/src/app/bridge/components/CodeGen.tsx
+++ b/apps/playground-web/src/app/bridge/components/CodeGen.tsx
@@ -160,6 +160,14 @@ tokenId: 2n,
? quotes(options.payOptions.buttonLabel)
: undefined,
transaction: transaction,
+ amountEditable:
+ widget === "buy" && options.payOptions.amountEditable === false
+ ? false
+ : undefined,
+ tokenEditable:
+ widget === "buy" && options.payOptions.tokenEditable === false
+ ? false
+ : undefined,
};
return `\
diff --git a/apps/playground-web/src/app/bridge/components/LeftSection.tsx b/apps/playground-web/src/app/bridge/components/LeftSection.tsx
index 8b97f19fdd4..bdc742a1137 100644
--- a/apps/playground-web/src/app/bridge/components/LeftSection.tsx
+++ b/apps/playground-web/src/app/bridge/components/LeftSection.tsx
@@ -259,6 +259,46 @@ export function LeftSection(props: {
+
+ {/* Editability Options */}
+
+
+
+
+ {
+ setOptions((v) => ({
+ ...v,
+ payOptions: {
+ ...v.payOptions,
+ tokenEditable: checked === true,
+ },
+ }));
+ }}
+ />
+
+
+
+
+ {
+ setOptions((v) => ({
+ ...v,
+ payOptions: {
+ ...v.payOptions,
+ amountEditable: checked === true,
+ },
+ }));
+ }}
+ />
+
+
+
+
)}
diff --git a/apps/playground-web/src/app/bridge/components/RightSection.tsx b/apps/playground-web/src/app/bridge/components/RightSection.tsx
index 766ea8d786d..add4c39dbf4 100644
--- a/apps/playground-web/src/app/bridge/components/RightSection.tsx
+++ b/apps/playground-web/src/app/bridge/components/RightSection.tsx
@@ -70,6 +70,8 @@ export function RightSection(props: {
currency={props.options.payOptions.currency}
showThirdwebBranding={props.options.payOptions.showThirdwebBranding}
receiverAddress={props.options.payOptions.receiverAddress}
+ amountEditable={props.options.payOptions.amountEditable}
+ tokenEditable={props.options.payOptions.tokenEditable}
key={JSON.stringify({
amount: props.options.payOptions.buyTokenAmount,
chain: props.options.payOptions.buyTokenChain,
diff --git a/apps/playground-web/src/app/bridge/components/buildBuyIframeUrl.ts b/apps/playground-web/src/app/bridge/components/buildBuyIframeUrl.ts
index 148f0ba52d8..536e5e8ed41 100644
--- a/apps/playground-web/src/app/bridge/components/buildBuyIframeUrl.ts
+++ b/apps/playground-web/src/app/bridge/components/buildBuyIframeUrl.ts
@@ -68,5 +68,14 @@ export function buildBuyIframeUrl(options: BridgeComponentsPlaygroundOptions) {
);
}
+ // Editability options
+ if (options.payOptions.amountEditable === false) {
+ url.searchParams.set("amountEditable", "false");
+ }
+
+ if (options.payOptions.tokenEditable === false) {
+ url.searchParams.set("tokenEditable", "false");
+ }
+
return url.toString();
}
diff --git a/apps/playground-web/src/app/bridge/components/types.ts b/apps/playground-web/src/app/bridge/components/types.ts
index 48812d3bf67..b2f66fd9048 100644
--- a/apps/playground-web/src/app/bridge/components/types.ts
+++ b/apps/playground-web/src/app/bridge/components/types.ts
@@ -59,5 +59,9 @@ export type BridgeComponentsPlaygroundOptions = {
currency?: SupportedFiatCurrency;
showThirdwebBranding: boolean;
+
+ // Editability options
+ amountEditable: boolean;
+ tokenEditable: boolean;
};
};
diff --git a/apps/playground-web/src/app/bridge/transaction-widget/TransactionPlayground.tsx b/apps/playground-web/src/app/bridge/transaction-widget/TransactionPlayground.tsx
index caeb4a6e4eb..b008cec4ff0 100644
--- a/apps/playground-web/src/app/bridge/transaction-widget/TransactionPlayground.tsx
+++ b/apps/playground-web/src/app/bridge/transaction-widget/TransactionPlayground.tsx
@@ -21,6 +21,8 @@ const defaultOptions: BridgeComponentsPlaygroundOptions = {
currency: "USD",
showThirdwebBranding: true,
receiverAddress: undefined,
+ amountEditable: true,
+ tokenEditable: true,
},
theme: {
darkColorOverrides: {},
diff --git a/apps/portal/src/app/bridge/buy-widget/iframe/page.mdx b/apps/portal/src/app/bridge/buy-widget/iframe/page.mdx
index 28794cc5440..f7a14ca1056 100644
--- a/apps/portal/src/app/bridge/buy-widget/iframe/page.mdx
+++ b/apps/portal/src/app/bridge/buy-widget/iframe/page.mdx
@@ -140,6 +140,33 @@ By default, the widget displays thirdweb branding at the bottom. You can hide th
+### Editability Options
+
+You can control whether users can edit certain fields in the widget.
+
+
+
+
+By default, users can change the token they want to purchase.
+
+You can disable this by setting the `tokenEditable` query parameter to `false`.
+
+
+
+
+
+
+
+By default, users can edit the purchase amount.
+
+You can disable this by setting the `amountEditable` query parameter to `false`.
+
+
+
+
+
+
+
## Listening for Events
The buy widget iframe sends events to the parent window using `postMessage` when a purchase succeeds or fails.
diff --git a/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx b/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx
index ce1bc57231a..6f4be0889fb 100644
--- a/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx
+++ b/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx
@@ -213,6 +213,16 @@ export type BuyWidgetProps = {
* Callback to be called when the user disconnects the active wallet.
*/
onDisconnect?: () => void;
+
+ /**
+ * By default the token amount is editable. Set this to false to disable editing the token amount
+ */
+ amountEditable?: boolean;
+
+ /**
+ * By default the token selection is editable. Set this to false to disable editing the token selection.
+ */
+ tokenEditable?: boolean;
};
/**
@@ -490,6 +500,12 @@ function BridgeWidgetContent(
};
});
+ const amountEditable =
+ props.amountEditable === undefined ? true : props.amountEditable;
+
+ const tokenEditable =
+ props.tokenEditable === undefined ? true : props.tokenEditable;
+
if (screen.id === "1:buy-ui") {
return (
);
}
diff --git a/packages/thirdweb/src/react/web/ui/Bridge/FundWallet.tsx b/packages/thirdweb/src/react/web/ui/Bridge/FundWallet.tsx
index a0490e05a6e..3d06ae934d7 100644
--- a/packages/thirdweb/src/react/web/ui/Bridge/FundWallet.tsx
+++ b/packages/thirdweb/src/react/web/ui/Bridge/FundWallet.tsx
@@ -113,6 +113,16 @@ type FundWalletProps = {
description: string | undefined;
image: string | undefined;
};
+
+ /**
+ * Whether the user can edit the amount. Defaults to true.
+ */
+ amountEditable: boolean;
+
+ /**
+ * Whether the user can edit the token selection. Defaults to true.
+ */
+ tokenEditable: boolean;
};
export type SelectedToken =
@@ -264,6 +274,8 @@ export function FundWallet(props: FundWalletProps) {
setDetailsModalOpen(true);
}}
currency={props.currency}
+ amountEditable={props.amountEditable}
+ tokenEditable={props.tokenEditable}
/>
{receiver && isReceiverDifferentFromActiveWallet && (
@@ -415,6 +427,8 @@ function TokenSection(props: {
};
onWalletClick: () => void;
presetOptions: [number, number, number];
+ amountEditable: boolean;
+ tokenEditable: boolean;
}) {
const theme = useCustomTheme();
const chainQuery = useBridgeChain({
@@ -467,6 +481,7 @@ function TokenSection(props: {
client={props.client}
onSelectToken={props.onSelectToken}
chain={chain}
+ disabled={props.tokenEditable === false}
/>
@@ -479,6 +494,7 @@ function TokenSection(props: {
value,
});
}}
+ disabled={props.amountEditable === false}
style={{
border: "none",
boxShadow: "none",
@@ -527,6 +543,7 @@ function TokenSection(props: {
value,
});
}}
+ disabled={props.amountEditable === false}
style={{
border: "none",
boxShadow: "none",
@@ -541,36 +558,41 @@ function TokenSection(props: {
)}
-
-
{/* suggested amounts */}
-
- {props.presetOptions.map((amount) => (
-
- ))}
-
+ {props.amountEditable && (
+ <>
+
+
+ {props.presetOptions.map((amount) => (
+
+ ))}
+
+ >
+ )}
{/* balance */}
diff --git a/packages/thirdweb/src/react/web/ui/Bridge/common/selected-token-button.tsx b/packages/thirdweb/src/react/web/ui/Bridge/common/selected-token-button.tsx
index 50538e2b1ad..b1c5ff73d5b 100644
--- a/packages/thirdweb/src/react/web/ui/Bridge/common/selected-token-button.tsx
+++ b/packages/thirdweb/src/react/web/ui/Bridge/common/selected-token-button.tsx
@@ -27,21 +27,26 @@ export function SelectedTokenButton(props: {
client: ThirdwebClient;
onSelectToken: () => void;
chain: BridgeChain | undefined;
+ disabled?: boolean;
}) {
const theme = useCustomTheme();
return (
);
}
diff --git a/packages/thirdweb/src/react/web/ui/components/buttons.tsx b/packages/thirdweb/src/react/web/ui/components/buttons.tsx
index a327fcf40b9..5f6c037041c 100644
--- a/packages/thirdweb/src/react/web/ui/components/buttons.tsx
+++ b/packages/thirdweb/src/react/web/ui/components/buttons.tsx
@@ -31,7 +31,7 @@ export const Button = /* @__PURE__ */ StyledButton((props: ButtonProps) => {
}
return {
all: "unset",
- "&:active": {
+ "[&:active]:not([disabled])": {
transform: "translateY(1px)",
},
"&[data-disabled='true']": {
diff --git a/packages/thirdweb/src/stories/BuyWidget.stories.tsx b/packages/thirdweb/src/stories/BuyWidget.stories.tsx
index e686ea8d701..e768158a713 100644
--- a/packages/thirdweb/src/stories/BuyWidget.stories.tsx
+++ b/packages/thirdweb/src/stories/BuyWidget.stories.tsx
@@ -63,6 +63,43 @@ export function BuyBaseUSDC() {
);
}
+export function TokenNotEditable() {
+ return (
+
+ );
+}
+
+export function AmountNotEditable() {
+ return (
+
+ );
+}
+
+export function TokenAndAmountNotEditable() {
+ return (
+
+ );
+}
+
export function CustomTitleDescriptionAndButtonLabel() {
return (