diff --git a/apps/portal/src/app/bridge/bridge-widget-script/bridge-widget-dark.png b/apps/portal/src/app/bridge/bridge-widget-script/bridge-widget-dark.png new file mode 100644 index 00000000000..e670a9610dc Binary files /dev/null and b/apps/portal/src/app/bridge/bridge-widget-script/bridge-widget-dark.png differ diff --git a/apps/portal/src/app/bridge/bridge-widget-script/bridge-widget-light.png b/apps/portal/src/app/bridge/bridge-widget-script/bridge-widget-light.png new file mode 100644 index 00000000000..aa5371887c2 Binary files /dev/null and b/apps/portal/src/app/bridge/bridge-widget-script/bridge-widget-light.png differ diff --git a/apps/portal/src/app/bridge/bridge-widget-script/page.mdx b/apps/portal/src/app/bridge/bridge-widget-script/page.mdx new file mode 100644 index 00000000000..27edc9542a4 --- /dev/null +++ b/apps/portal/src/app/bridge/bridge-widget-script/page.mdx @@ -0,0 +1,467 @@ +import { + Details, + createMetadata, + DocImage +} from "@doc"; +import bridgeWidgetDark from "./bridge-widget-dark.png"; +import bridgeWidgetLight from "./bridge-widget-light.png"; + + +export const metadata = createMetadata({ + image: { + title: "BridgeWidget Script", + icon: "payments", + }, + title: "Bridge Widget", + description: "Add a widget to add cross swaps and fiat onramp to your app", +}); + +# BridgeWidget Script + +The BridgeWidget Script makes it easy to embed cross-chain swaps and fiat onramp UI into your app. Just add a script tag to your HTML and get a fully customizable widget — no build setup required. + +## Key Features +- Cross-chain token swaps across 80+ blockchains +- Fiat onramp support to buy tokens with credit/debit cards +- Customizable UI - use prebuilt themes or override with your brand colors +- Prefill token selections for a smoother user experience +- Display fiat values in multiple currencies +- Event callbacks to track user actions (success, error, cancel, disconnect) + + +
+ +
+
+ +
+ + +## Script Integration + +```html + + + + +
+ + + +``` + + +## Options + +You can customize theme, currencies, token selections, and more. See the full list of options below + +
+ +```ts +type Options = { + clientId: string; + theme?: "dark" | "light" | { + type: "dark" | "light"; + accentButtonBg?: string; + accentButtonText?: string; + accentText?: string; + borderColor?: string; + connectedButtonBg?: string; + connectedButtonBgHover?: string; + danger?: string; + inputAutofillBg?: string; + modalBg?: string; + modalOverlayBg?: string; + primaryButtonBg?: string; + primaryButtonText?: string; + primaryText?: string; + scrollbarBg?: string; + secondaryButtonBg?: string; + secondaryButtonHoverBg?: string; + secondaryButtonText?: string; + secondaryIconColor?: string; + secondaryIconHoverBg?: string; + secondaryIconHoverColor?: string; + secondaryText?: string; + selectedTextBg?: string; + selectedTextColor: string; + separatorLine?: string; + skeletonBg: string; + success?: string; + tertiaryBg?: string; + tooltipBg?: string; + tooltipText?: string; + }; + showThirdwebBranding?: boolean; + currency?: SupportedFiatCurrency; + swap?: { + className?: string; + style?: React.CSSProperties; + onSuccess?: (quote: SwapPreparedQuote) => void; + onError?: (error: Error, quote: SwapPreparedQuote) => void; + onCancel?: (quote: SwapPreparedQuote) => void; + onDisconnect?: () => void; + persistTokenSelections?: boolean; + prefill?: { + buyToken?: { + tokenAddress?: string; + chainId: number; + amount?: string; + }; + sellToken?: { + tokenAddress?: string; + chainId: number; + amount?: string; + }; + }; + }; + buy: { + amount: string; + chainId: number; + tokenAddress?: string; + buttonLabel?: string; + onCancel?: (quote: BuyOrOnrampPrepareResult | undefined) => void; + onError?: ( + error: Error, + quote: BuyOrOnrampPrepareResult | undefined, + ) => void; + onSuccess?: (quote: BuyOrOnrampPrepareResult) => void; + className?: string; + country?: string; + presetOptions?: [number, number, number]; + purchaseData?: PurchaseData; + }; +} +``` + + +
+ + + +### clientId +Set your Project's client ID to identify your project. You create a project for free on [thirdweb dashboard](https://thirdweb.com/team) + + +### swap +The options to configure the "Swap" tab + +```ts +type Swap = { + className?: string; + style?: React.CSSProperties; + onSuccess?: (quote: SwapPreparedQuote) => void; + onError?: (error: Error, quote: SwapPreparedQuote) => void; + onCancel?: (quote: SwapPreparedQuote) => void; + onDisconnect?: () => void; + persistTokenSelections?: boolean; + prefill?: { + buyToken?: { + tokenAddress?: string; + chainId: number; + amount?: string; + }; + sellToken?: { + tokenAddress?: string; + chainId: number; + amount?: string; + }; + }; + } +``` + + +
+ +You can prefill Buy and/or Sell tokens for the swap tab. If `tokenAddress` is not provided, the native token will be used. Here are some examples: + + +#### Set an ERC20 token as the buy token + +```js +BridgeWidget.render(container, { + clientId: "your-thirdweb-client-id", + swap: { + prefill: { + // Base USDC + buyToken: { + chainId: 8453, + tokenAddress: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + }, + }, + }, +}); +``` + +#### Set a native token as the sell token + +```js +BridgeWidget.render(container, { + clientId: "your-thirdweb-client-id", + swap: { + prefill: { + // Base native token (ETH) + sellToken: { + chainId: 8453, + }, + }, + }, +}); +``` + +#### Set amount and token to Buy by default + +```js +BridgeWidget.render(container, { + clientId: "your-thirdweb-client-id", + swap: { + prefill: { + buyToken: { + chainId: 8453, + amount: "0.1", + tokenAddress: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + }, + }, + }, +}); +``` + +#### Set both buy and sell tokens by default + +```ts +BridgeWidget.render(container, { + clientId: "your-thirdweb-client-id", + swap: { + prefill: { + // Base USDC + buyToken: { + chainId: 8453, + tokenAddress: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + }, + // Polygon native token (POL) + sellToken: { + chainId: 137, + }, + }, + }, +}); +``` + +
+ + +
+ +Whether to persist the token selections to localStorage so that if the user revisits the widget, the last used tokens are pre-selected. + +The last used tokens do not override the tokens specified in the `prefill` option. By default, it is set to `true`. + +
+ + +
+ +Pass a callback to be called when the user cancels the purchase. + +
+ +
+ +Pass a callback to be called when the user encounters an error during the purchase. + +
+ +
+ +Pass a callback to be called when the user successfully completes the purchase. + +
+ +
+ +Apply a custom class name to the "Buy" tab content container. + +
+ +
+ +Pass a callback to be called when the user disconnects the active wallet. + +
+ + + + +### buy + +The options to configure the "Buy" tab UI. + + +```ts +type Buy = { + amount: string; // Required + chainId: number; // Required + tokenAddress?: string; + buttonLabel?: string; + onCancel?: (quote: BuyOrOnrampPrepareResult | undefined) => void; + onError?: ( + error: Error, + quote: BuyOrOnrampPrepareResult | undefined, + ) => void; + onSuccess?: (quote: BuyOrOnrampPrepareResult) => void; + className?: string; + country?: string; + presetOptions?: [number, number, number]; + } +``` + + +
+ +Set the default token amount shown in the "Buy" tab. + +
+ +
+ +Specify which chain should be selected in the "Buy" tab. + +
+ +
+ +Specify which token should be selected in the "Buy" tab. If not specified, the native token of the selected chain will be selected. + +
+ +
+ +Override the label for main action button + +
+ +
+ +Pass a callback to be called when the user cancels the purchase. + +
+ +
+ +Pass a callback to be called when the user encounters an error during the purchase. + +
+ +
+ +Pass a callback to be called when the user successfully completes the purchase. + +
+ +
+ +Apply a custom class name to the "Buy" tab content container. + +
+ +
+ +The user's ISO 3166 alpha-2 country code. This is used to determine onramp provider support. + +
+ +
+ +Preset fiat amounts to display in the UI. Defaults to [5, 10, 20]. + +
+ + + + + + + + +### theme + +Set the theme for the widget. You can either set it to `"dark"`, `"light"` or overrides some or all the colors by passing an object. By default it set to `"dark"`. + +When overriding the colors, you must set the `type` to either `"dark"` or `"light"` so that the widget knows which theme to apply the overrides to. + + +```ts +type Theme = "dark" | "light" | { + type: "dark" | "light"; // required + accentButtonBg?: string; + accentButtonText?: string; + accentText?: string; + borderColor?: string; + connectedButtonBg?: string; + connectedButtonBgHover?: string; + danger?: string; + inputAutofillBg?: string; + modalBg?: string; + modalOverlayBg?: string; + primaryButtonBg?: string; + primaryButtonText?: string; + primaryText?: string; + scrollbarBg?: string; + secondaryButtonBg?: string; + secondaryButtonHoverBg?: string; + secondaryButtonText?: string; + secondaryIconColor?: string; + secondaryIconHoverBg?: string; + secondaryIconHoverColor?: string; + secondaryText?: string; + selectedTextBg?: string; + selectedTextColor: string; + separatorLine?: string; + skeletonBg: string; + success? : string; + tertiaryBg?: string; + tooltipBg?: string; + tooltipText?: string; +} +``` + +#### Example + +```js +BridgeWidget.render(container, { + clientId: "your-thirdweb-client-id", + theme: { + type: "dark", + colors: { + modalBg: "black", + primaryText: "white", + }, + } +}); +``` + + +### currency + +The token amounts fiat values will be displayed in this currency. By default, it is set to `"USD"`. + + +```ts +type Currency = "USD" | "EUR" | "GBP" | "JPY" | "KRW" | "CNY" | "INR" | "NOK" | "SEK" | "CHF" | "AUD" | "CAD" | "NZD" | "MXN" | "BRL" | "CLP" | "CZK" | "DKK" | "HKD" | "HUF" | "IDR" | "ILS" | "ISK"; +``` + + +### showThirdwebBranding + +Whether to show thirdweb branding at the bottom of the widget. By default, it is set to `true`. diff --git a/apps/portal/src/app/bridge/page.mdx b/apps/portal/src/app/bridge/page.mdx index f1381c3b2a6..7fcd9587974 100644 --- a/apps/portal/src/app/bridge/page.mdx +++ b/apps/portal/src/app/bridge/page.mdx @@ -102,17 +102,17 @@ const preparedQuote = await Bridge.Buy.prepare({ - The quickest way to setup Bridge in your React app is with the [`BuyWidget`](/references/typescript/v5/widgets/BuyWidget) component. - + The quickest way to setup Bridge in your React app is with the [`SwapWidget`](/references/typescript/v5/widgets/SwapWidget) component. + ### Live Playground - + ### Installation Install the thirdweb SDK in your React project: @@ -127,7 +127,7 @@ const preparedQuote = await Bridge.Buy.prepare({ ### Create a Client - First, create a client file (e.g., `thirdwebClient.ts`) for reuse throughout your app: + First, create a client file for reuse throughout your app: ```typescript // thirdwebClient.ts @@ -140,7 +140,7 @@ const preparedQuote = await Bridge.Buy.prepare({ ### Setup the Provider - Wrap your application with the ThirdwebProvider: + Wrap your application with the `ThirdwebProvider` ```tsx // app.tsx / _app.tsx @@ -155,21 +155,17 @@ const preparedQuote = await Bridge.Buy.prepare({ } ``` - ### Buy Widget + ### Add Swap Widget - Use the BuyWidget to let users purchase tokens: + Use the SwapWidget to let users swap tokens ```tsx - import { BuyWidget } from "thirdweb/react"; - import { base } from "thirdweb/chains"; + import { SwapWidget } from "thirdweb/react"; - function PaymentComponent() { + function Example() { return ( - ); } diff --git a/apps/portal/src/app/bridge/sidebar.tsx b/apps/portal/src/app/bridge/sidebar.tsx index b4eaefbbf7a..287f1ec677d 100644 --- a/apps/portal/src/app/bridge/sidebar.tsx +++ b/apps/portal/src/app/bridge/sidebar.tsx @@ -32,6 +32,10 @@ export const sidebar: SideBar = { href: `${bridgeSlug}/routes`, name: "Get Routes", }, + { + href: `${bridgeSlug}/bridge-widget-script`, + name: "BridgeWidget Script", + }, ], name: "Guides", }, diff --git a/apps/portal/src/components/Document/Details.tsx b/apps/portal/src/components/Document/Details.tsx index 9fb6e1b55c3..f5206115301 100644 --- a/apps/portal/src/components/Document/Details.tsx +++ b/apps/portal/src/components/Document/Details.tsx @@ -30,7 +30,7 @@ export function Details(props: {
-
{props.children}
+
+ {props.children} +
); } diff --git a/apps/portal/src/components/Document/Heading.tsx b/apps/portal/src/components/Document/Heading.tsx index ffafcd05c11..c04ab9b8a2d 100644 --- a/apps/portal/src/components/Document/Heading.tsx +++ b/apps/portal/src/components/Document/Heading.tsx @@ -46,7 +46,7 @@ export function Heading(props: { case 3: { return ( diff --git a/apps/portal/src/components/Document/Paragraph.tsx b/apps/portal/src/components/Document/Paragraph.tsx index a3938c275c5..fc23b9e4144 100644 --- a/apps/portal/src/components/Document/Paragraph.tsx +++ b/apps/portal/src/components/Document/Paragraph.tsx @@ -5,6 +5,6 @@ export function Paragraph(props: { className?: string; }) { return ( -

{props.children}

+

{props.children}

); } diff --git a/apps/portal/src/components/ui/tabs.tsx b/apps/portal/src/components/ui/tabs.tsx index c083eacdb00..501c8980c2e 100644 --- a/apps/portal/src/components/ui/tabs.tsx +++ b/apps/portal/src/components/ui/tabs.tsx @@ -32,7 +32,7 @@ const TabsTrigger = React.forwardRef< "border-transparent border-b text-muted-foreground ring-offset-700 transition-all", "hover:text-foreground hover:bg-accent data-[state=active]:text-foreground", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", - "data-[state=active]:before:opacity-100 before:absolute before:opacity-0 before:border-b before:left-0 before:right-0 before:bottom-[-5px] before:transition-opacity before:duration-300", + "data-[state=active]:before:opacity-100 before:absolute before:opacity-0 before:border-b-2 before:border-foreground before:left-0 before:right-0 before:bottom-[-5px] before:transition-opacity before:duration-300", className, )} ref={ref} diff --git a/packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx b/packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx index 89bc35afe58..f27e5a800ef 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx @@ -48,7 +48,7 @@ export type SwapWidgetProps = { */ client: ThirdwebClient; /** - * The prefill Buy and/or Sell tokens for the swap widget. If `tokenAddress` is not provided, the native token will be used + * Prefill Buy and/or Sell tokens for the swap widget. If `tokenAddress` is not provided, the native token will be used * * @example *