npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@shapeshiftoss/swap-widget

v0.5.2

Published

Embeddable swap widget using ShapeShift API

Downloads

523

Readme

@shapeshiftoss/swap-widget

An embeddable React widget that enables multi-chain token swaps using ShapeShift's aggregation API. Drop it into your app to offer EVM, UTXO, and Solana swaps with minimal configuration.

This README is the canonical reference for the swap widget. Other docs (including the ShapeShift Public API docs) link here.

Table of Contents

Installation

npm install @shapeshiftoss/swap-widget

Peer Dependencies

The widget relies on React, wagmi/viem, React Query, and Reown AppKit (used internally for wallet connection). The widget initializes AppKit with the EVM, Bitcoin, and Solana adapters at load, so all of these peers are required — install them alongside the package:

npm install react react-dom \
  wagmi @wagmi/core viem \
  @tanstack/react-query \
  @reown/appkit @reown/appkit-adapter-wagmi \
  @reown/appkit-adapter-bitcoin @reown/appkit-adapter-solana \
  @solana/wallet-adapter-wallets @solana/web3.js
  • React 18 or 19 is supported (^18.0.0 || ^19.0.0).

Import the stylesheet

The widget ships a stylesheet that must be imported once for it to render correctly:

import '@shapeshiftoss/swap-widget/style.css'

Quick Start

import '@shapeshiftoss/swap-widget/style.css'

import { SwapWidget } from '@shapeshiftoss/swap-widget'

function App() {
  return (
    <SwapWidget
      // Initializes the built-in wallet connection. Optional if your app already
      // initializes Reown AppKit — see "Wallet Connection" below.
      walletConnectProjectId="your-walletconnect-project-id"
      // Optional: attribute swaps to your affiliate account.
      partnerCode="your-partner-code"
      theme="dark"
      onSwapSuccess={txHash => console.log('Success:', txHash)}
      onSwapError={error => console.error('Error:', error)}
    />
  )
}

Wallet Connection

The widget connects wallets through Reown AppKit and provides the WagmiProvider / QueryClient it needs — you don't wrap it in your own.

Initializing AppKit

The widget renders nothing until AppKit is initialized. There are two ways to satisfy this:

  • Let the widget initialize AppKit (default). Pass walletConnectProjectId and the widget creates and owns its own AppKit instance. Get a free project ID at https://dashboard.reown.com.

    <SwapWidget walletConnectProjectId="your-walletconnect-project-id" />
  • Reuse your app's existing AppKit. If your host app already calls createAppKit() (with a wagmi EVM adapter), omit walletConnectProjectId. The widget detects the shared AppKit singleton, reads the wagmi config off it, and provides its own WagmiProvider / QueryClient from that config — you wrap the widget in no providers of your own. Pair this with showConnectButton={false} to drive connection entirely from your own UI. See src/demo/ExternalWalletApp.tsx for a full host example.

    Two requirements for this mode:

    • Initialize AppKit before the widget mounts. The widget reads the AppKit singleton when it mounts and does not poll for late initialization — if AppKit isn't up yet, the widget renders nothing.
    • Dedupe the AppKit/wagmi packages. @reown/appkit*, wagmi, and viem must resolve to a single shared copy in your app, so the widget and your app share one AppKit instance and one wagmi state. A duplicated copy means the widget reads an empty store and shows no connection.

The header shows a built-in Connect button by default; set showConnectButton={false} to hide it and drive connection from your own UI.

Supported wallet namespaces

Once connected, the widget can sign and broadcast transactions for three wallet namespaces:

| Namespace | Chains | Example wallets | | --------- | ------------------------------- | -------------------------------- | | eip155 | All supported EVM chains | MetaMask, WalletConnect, Rabby | | bip122 | Bitcoin and other UTXO chains | WalletConnect-compatible wallets | | solana | Solana | Phantom, Solflare |

The header shows a Connect button by default (toggle with showConnectButton) that opens the AppKit modal. Swaps whose sell asset is not in an executable namespace (see Supported Chains) redirect to app.shapeshift.com when allowShapeshiftRedirect is enabled.

Props Reference

SwapWidgetProps

| Prop | Type | Default | Description | | ------------------------ | ----------------------------------------------- | ------------------ | -------------------------------------------------------------------------------------------------------- | | walletConnectProjectId | string | – | Reown AppKit / WalletConnect project ID. The widget uses it to initialize AppKit. Required unless your host app already initializes AppKit (see Wallet Connection). | | partnerCode | string | – | Your registered partner code for affiliate fee attribution. See Partner Codes. | | apiBaseUrl | string | https://api.shapeshift.com | Override the API base URL. Useful for testing or custom deployments. | | defaultSellAsset | Asset | ETH on Ethereum | Initial asset to sell. | | defaultBuyAsset | Asset | USDC on Ethereum | Initial asset to buy. | | sellFilters | SwapWidgetFilters | {} | Restrict which chains/assets are selectable for the sell side. See Filtering. | | buyFilters | SwapWidgetFilters | {} | Restrict which chains/assets are selectable for the buy side. | | allowedSwapperNames | SwapperName[] | all enabled | Limit quotes to specific swappers. See Supported Swappers. | | allowShapeshiftRedirect| boolean | true | When a swap isn't executable in-widget, redirect to app.shapeshift.com instead of hiding it. | | isBuyAssetLocked | boolean | false | Prevent the user from changing the buy asset. | | theme | ThemeMode \| ThemeConfig | "dark" | Theme mode ("light" or "dark") or a full theme configuration object. See Theming. | | defaultSlippage | string | "0.5" | Default slippage tolerance, as a percentage string. | | showPoweredBy | boolean | true | Show the "Powered by ShapeShift" footer. | | showConnectButton | boolean | true | Show the built-in Connect button in the widget header. | | ratesRefetchInterval | number | 15000 | How often (ms) to refetch swap rates. | | onSwapSuccess | (txHash: string) => void | – | Called when a swap transaction succeeds. | | onSwapError | (error: Error) => void | – | Called when a swap transaction fails. |

Filtering Chains and Assets

Restrict the sell and/or buy asset selectors independently via the sellFilters and buyFilters props. Both accept the same shape:

type SwapWidgetFilters = {
  allowedChainIds?: ChainId[] // If set, only these chains are selectable
  disabledChainIds?: ChainId[] // Hide these chains
  allowedAssetIds?: AssetId[] // If set, only these assets are selectable
  disabledAssetIds?: AssetId[] // Hide these assets
}
import { EVM_CHAIN_IDS, SwapWidget } from '@shapeshiftoss/swap-widget'

function App() {
  return (
    <SwapWidget
      walletConnectProjectId="your-walletconnect-project-id"
      partnerCode="your-partner-code"
      // Only allow selling ETH-chain, Polygon, and Arbitrum assets
      sellFilters={{
        allowedChainIds: [EVM_CHAIN_IDS.ethereum, EVM_CHAIN_IDS.polygon, EVM_CHAIN_IDS.arbitrum],
      }}
      // Hide a specific buy token
      buyFilters={{
        disabledAssetIds: ['eip155:1/erc20:0x...'],
      }}
      theme="dark"
    />
  )
}

Theming

The widget supports a simple light/dark mode or a full theme configuration object.

Simple theme mode

<SwapWidget walletConnectProjectId="..." theme="dark" />
// or
<SwapWidget walletConnectProjectId="..." theme="light" />

Custom theme configuration

import { SwapWidget } from '@shapeshiftoss/swap-widget'
import type { ThemeConfig } from '@shapeshiftoss/swap-widget'

const customTheme: ThemeConfig = {
  mode: 'dark', // required
  accentColor: '#3861fb',
  backgroundColor: '#0a0a14',
  cardColor: '#12121c',
  textColor: '#ffffff',
  borderRadius: '12px',
  fontFamily: 'Inter, sans-serif',
  buttonVariant: 'filled',
}

function App() {
  return <SwapWidget walletConnectProjectId="..." theme={customTheme} />
}

ThemeConfig properties

| Property | Type | Description | | -------------------- | ------------------------ | ---------------------------------------------------- | | mode | "light" \| "dark" | Base theme mode. Required. | | accentColor | string | Primary accent color (buttons, focus states). | | backgroundColor | string | Widget background color. | | cardColor | string | Card / panel background color. | | textColor | string | Primary text color. | | secondaryTextColor | string | Secondary text color. | | mutedTextColor | string | Muted/tertiary text color. | | inputColor | string | Input field background color. | | hoverColor | string | Hover background color. | | borderColor | string | Border color. | | borderRadius | string | Base border radius for UI elements (e.g. "12px"). | | fontFamily | string | Font family for the widget. | | buttonVariant | "filled" \| "outline" | Primary button style. |

Examples

Basic usage

import { SwapWidget } from '@shapeshiftoss/swap-widget'

function App() {
  return <SwapWidget walletConnectProjectId="..." partnerCode="your-partner-code" theme="dark" />
}

Custom default assets

import { SwapWidget } from '@shapeshiftoss/swap-widget'
import type { Asset } from '@shapeshiftoss/swap-widget'

const defaultSellAsset: Asset = {
  assetId: 'eip155:137/slip44:966',
  chainId: 'eip155:137',
  symbol: 'POL',
  name: 'Polygon',
  precision: 18,
}

const defaultBuyAsset: Asset = {
  assetId: 'eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174',
  chainId: 'eip155:137',
  symbol: 'USDC',
  name: 'USD Coin',
  precision: 6,
}

function App() {
  return (
    <SwapWidget
      walletConnectProjectId="..."
      partnerCode="your-partner-code"
      defaultSellAsset={defaultSellAsset}
      defaultBuyAsset={defaultBuyAsset}
      theme="dark"
    />
  )
}

Locking the buy asset

Use isBuyAssetLocked so users can only change the sell side — useful when you want all swaps to end in a specific token.

<SwapWidget
  walletConnectProjectId="..."
  partnerCode="your-partner-code"
  defaultBuyAsset={defaultBuyAsset}
  isBuyAssetLocked
  theme="dark"
/>

Exported Types

import type {
  Asset,
  AssetId,
  Chain,
  ChainId,
  SwapWidgetFilters,
  SwapWidgetProps,
  ThemeConfig,
  ThemeMode,
  TradeQuote,
  TradeRate,
} from '@shapeshiftoss/swap-widget'

SwapperName is exported as a runtime value (an enum) — import it from the value position, not as a type.

Asset

type Asset = {
  assetId: AssetId // CAIP-19, e.g. "eip155:1/slip44:60"
  chainId: ChainId // CAIP-2, e.g. "eip155:1"
  symbol: string // e.g. "ETH"
  name: string // e.g. "Ethereum"
  precision: number // e.g. 18
  icon?: string
  color?: string
  networkName?: string
  networkIcon?: string
  explorer?: string
  explorerTxLink?: string
  explorerAddressLink?: string
  relatedAssetKey?: AssetId | null
}

Exported Utilities

import {
  COSMOS_CHAIN_IDS,
  EVM_CHAIN_IDS,
  OTHER_CHAIN_IDS,
  REDIRECT_ONLY_CHAIN_IDS,
  SwapperName,
  UTXO_CHAIN_IDS,
  formatAmount,
  getBaseAsset,
  getChainColor,
  getChainIcon,
  getChainName,
  getChainType,
  getEvmNetworkId,
  getExplorerTxLink,
  isEvmChainId,
  isWidgetExecutableChainId,
  isWidgetSupportedChainId,
  parseAmount,
  truncateAddress,
} from '@shapeshiftoss/swap-widget'

Chain helpers

| Function | Signature | Description | | --------------------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------ | | isEvmChainId | (chainId: string) => boolean | Whether a chain ID is an EVM chain. | | getEvmNetworkId | (chainId: string) => number | Extract the numeric network ID from a CAIP-2 EVM chain ID. | | getChainType | (chainId: string) => "evm" \| "utxo" \| "cosmos" \| "solana" \| "other" | Classify a chain by namespace. | | isWidgetSupportedChainId | (chainId: string) => boolean | Whether the widget lists assets on this chain. | | isWidgetExecutableChainId | (chainId: string) => boolean | Whether the widget can sign/execute swaps on this chain in-app. | | getChainName | (chainId: ChainId) => string | Display name for a chain. | | getChainIcon | (chainId: ChainId) => string \| undefined | Icon URL for a chain. | | getChainColor | (chainId: ChainId) => string | Brand color for a chain. | | getBaseAsset | (chainId: ChainId) => Asset \| undefined | Native asset for a chain. | | getExplorerTxLink | (chainId: ChainId) => string \| undefined | Block-explorer transaction link template. |

Amount and address formatting

| Function | Signature | Description | | ----------------- | -------------------------------------------------------------------- | ---------------------------------------------------- | | formatAmount | (amount: string, decimals: number, maxDecimals?: number) => string | Format a base-unit amount for display. | | parseAmount | (amount: string, decimals: number) => string | Parse a human-readable amount into base units. | | truncateAddress | (address: string, chars?: number) => string | Truncate an address (e.g. 0x1234...5678). |

Chain ID constants

const EVM_CHAIN_IDS = {
  ethereum: 'eip155:1',
  arbitrum: 'eip155:42161',
  optimism: 'eip155:10',
  polygon: 'eip155:137',
  base: 'eip155:8453',
  avalanche: 'eip155:43114',
  bsc: 'eip155:56',
  gnosis: 'eip155:100',
  monad: 'eip155:143',
  megaEth: 'eip155:4326',
  hyperEvm: 'eip155:999',
  plasma: 'eip155:9745',
  katana: 'eip155:747474',
}

const UTXO_CHAIN_IDS = {
  bitcoin: 'bip122:000000000019d6689c085ae165831e93',
  bitcoinCash: 'bip122:000000000000000000651ef99cb9fcbe',
  dogecoin: 'bip122:00000000001a91e3dace36e2be3bf030',
  litecoin: 'bip122:12a765e31ffd4059bada1e25190f6e98',
}

const COSMOS_CHAIN_IDS = {
  cosmos: 'cosmos:cosmoshub-4',
  thorchain: 'cosmos:thorchain-1',
  mayachain: 'cosmos:mayachain-mainnet-v1',
}

const OTHER_CHAIN_IDS = {
  solana: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
}

// Listed in the asset selector, but swaps redirect to app.shapeshift.com (not executed in-widget)
const REDIRECT_ONLY_CHAIN_IDS = {
  zcash: 'bip122:00040fe8ec8471911baa1db1266ea15d',
  tron: 'tron:0x2b6653dc',
  sui: 'sui:35834a8a',
  ton: 'ton:mainnet',
  near: 'near:mainnet',
  starknet: 'starknet:SN_MAIN',
}

Exported Hooks

import {
  useAssetById,
  useAssetSearch,
  useAssets,
  useAssetsByChainId,
  useChains,
} from '@shapeshiftoss/swap-widget'

| Hook | Description | | --------------------------------- | -------------------------------------------------------------- | | useAssets() | Fetch all available assets. | | useAssetById(assetId) | Fetch a single asset by ID. | | useChains() | Fetch all available chains with their native assets. | | useAssetsByChainId(chainId) | Fetch all assets for a specific chain. | | useAssetSearch(query, chainId?) | Search assets by symbol or name, optionally filtered by chain. |

These hooks must be used within a mounted <SwapWidget /> tree (they rely on the widget's internal React Query client).

Supported Chains

Assets on the following chains appear in the selector. Swaps are executed in-widget only for EVM, UTXO, and Solana assets (isWidgetExecutableChainId returns true). Cosmos-SDK and redirect-only chains are selectable but route the user to app.shapeshift.com to complete the swap (when allowShapeshiftRedirect is enabled).

| Chain | Chain ID | Type | Executable in-widget | | ----------------- | ----------------------------------------- | ------ | -------------------- | | Ethereum | eip155:1 | EVM | ✅ | | Arbitrum One | eip155:42161 | EVM | ✅ | | Optimism | eip155:10 | EVM | ✅ | | Polygon | eip155:137 | EVM | ✅ | | Base | eip155:8453 | EVM | ✅ | | Avalanche C-Chain | eip155:43114 | EVM | ✅ | | BNB Smart Chain | eip155:56 | EVM | ✅ | | Gnosis | eip155:100 | EVM | ✅ | | Monad | eip155:143 | EVM | ✅ | | MegaETH | eip155:4326 | EVM | ✅ | | HyperEVM | eip155:999 | EVM | ✅ | | Plasma | eip155:9745 | EVM | ✅ | | Katana | eip155:747474 | EVM | ✅ | | Bitcoin | bip122:000000000019d6689c085ae165831e93 | UTXO | ✅ | | Bitcoin Cash | bip122:000000000000000000651ef99cb9fcbe | UTXO | ✅ | | Dogecoin | bip122:00000000001a91e3dace36e2be3bf030 | UTXO | ✅ | | Litecoin | bip122:12a765e31ffd4059bada1e25190f6e98 | UTXO | ✅ | | Solana | solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp | Solana | ✅ | | Cosmos Hub | cosmos:cosmoshub-4 | Cosmos | ↗ redirect | | THORChain | cosmos:thorchain-1 | Cosmos | ↗ redirect | | MAYAChain | cosmos:mayachain-mainnet-v1 | Cosmos | ↗ redirect | | Zcash, Tron, Sui, TON, NEAR, Starknet | see REDIRECT_ONLY_CHAIN_IDS | Other | ↗ redirect |

Supported Swappers

The widget aggregates quotes across the protocols below and surfaces the best rate. Use allowedSwapperNames to restrict which are used.

  • NEAR Intents (SwapperName.NearIntents)
  • Relay (SwapperName.Relay)
  • THORChain (SwapperName.Thorchain)
  • MAYAChain (SwapperName.Mayachain)

The set of enabled swappers changes over time. Treat this list as current-at-publish; the authoritative source is the SwapperName enum exported by this package.

Partner Codes & Affiliate Revenue

Pass your registered partnerCode to attribute swaps to your affiliate account and earn revenue share. The widget forwards it to the ShapeShift Public API as the X-Partner-Code header, and the API applies your configured fee automatically.

<SwapWidget walletConnectProjectId="..." partnerCode="your-partner-code" />

See the Affiliate Program guide for how to obtain a partner code and how revenue attribution works.

Notes and Limitations

  • Self-contained providers. The widget renders its own WagmiProvider and React Query QueryClient. Don't wrap it in your own — and remember it renders nothing until AppKit is initialized, whether by walletConnectProjectId or by your host app (see Wallet Connection).
  • Balances and USD prices. When a wallet is connected, the widget shows balances and USD prices for the selected assets.
  • Redirects. Assets on non-executable chains (Cosmos, Zcash, Tron, Sui, TON, NEAR, Starknet) send the user to app.shapeshift.com to finish the swap, unless allowShapeshiftRedirect={false}.
  • Mobile responsive. The widget is designed to work on mobile as well as desktop.