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

@multisender.app/multisender-react-widget

v0.2.3

Published

## What is MultisenderWidget? MultisenderWidget is a plug-and-play React component designed for seamless integration of bulk token transfers (“multisend”) into any third-party application, dashboard, or custom frontend. The widget provides almost all the

Downloads

1,073

Readme

Multisender React Widget Documentation

What is MultisenderWidget?

MultisenderWidget is a plug-and-play React component designed for seamless integration of bulk token transfers (“multisend”) into any third-party application, dashboard, or custom frontend. The widget provides almost all the core features of the main Multisender.app platform:

Sending tokens to multiple recipients in a single transaction

  • Support for dozens of EVM networks
  • Intuitive UI for entering, uploading, and validating addresses and amounts
  • Integration with the Multisender smart contract, including real-time transaction status and error tracking
  • Flexible style customization via props and CSS

You don’t need to build your own multisend logic or UI—just embed the component and configure it with your parameters.

Supported Networks

Currently, MultisenderWidget supports bulk transfers on the following networks (list is regularly updated):

  • Ethereum Mainnet, Sepolia, Base, Base Sepolia
  • BNB Smart Chain (BSC), opBNB
  • Polygon, Polygon zkEVM
  • Arbitrum, Arbitrum Nova
  • Optimism, Mode, Mantle, Blast, Linea, Taiko, Scroll, Zircuit, Fraxtal
  • Moonbeam, Moonriver, Aurora, Gnosis, Celo, Metis, Fantom, Avalanche, Berachain, Cronos, Telos, IOTEX, ThunderCore, HarmonyOne, Soneium, Ink, Sonic, Kaia, ApeChain, Zetachain, UniChain, Worldchain
  • zkSync, zkSync Sepolia Testnet, Sei, Rootstock

If you need to add support for a custom network, please contact the Multisender.app team. Custom ChainConfig is not currently supported via widget props.

PostHog Analytics

PostHog is an analytics platform that can be integrated with MultisenderWidget to track user events (such as transaction start/completion, errors, clicks, and more). This helps you analyze user behavior and improve your interface.

How to enable:

  • To enable analytics, provide the posthogKey and posthogHost props.
  • These values are issued by the Multisender.app team upon request.
  • If these props are not provided, analytics will be disabled, and the widget will function normally without tracking.

Installation

Install the Multisender React Widget package using yarn:

yarn add @multisender/react-widget

Usage

AppKit Initialization

Before using MultisenderWidget, you must initialize appKit with the same wagmiConfig that will be passed to the widget:

import { createConfig, http, fallback } from 'wagmi';
import { sepolia, mainnet, rootstock } from 'wagmi/chains';
import { createAppKit, WagmiAdapter, AppKitNetwork } from '@reown/appkit';

const networks: AppKitNetwork[] = [sepolia, rootstock, mainnet];

export const widgetConfig: Record<number, ChainConfig> = {
  [sepolia.id]: {
    id: sepolia.id,
    name: sepolia.name,
    blockExplorerUrl: {
      tx: 'https://eth-sepolia.blockscout.com/tx/',
      address: 'https://eth-sepolia.blockscout.com/address/',
    },
    rpcUrls: ['https://eth-sepolia.g.alchemy.com/v2/*****'],
    blockScoutApiUrl: 'https://eth-sepolia.blockscout.com',
  },
  [mainnet.id]: {
    id: mainnet.id,
    name: mainnet.name,
    blockExplorerUrl: {
      tx: 'https://eth.blockscout.com/tx/',
      address: 'https://eth.blockscout.com/address/',
    },
    rpcUrls: ['https://eth-mainnet.g.alchemy.com/v2/*****'],
    blockScoutApiUrl: 'https://eth.blockscout.com',
  },
  [rootstock.id]: {
    id: rootstock.id,
    name: rootstock.name,
    blockExplorerUrl: {
      tx: 'https://rootstock.blockscout.com/tx/',
      address: 'https://rootstock.blockscout.com/address/',
    },
    rpcUrls: ['https://rootstock-mainnet.g.alchemy.com/v2/*****'],
    blockScoutApiUrl: 'https://rootstock.blockscout.com',
  },
}

const projectId = 'your-project-id'; // walletConnect project id

export function initAdapters() {
  const wagmiAdapter = new WagmiAdapter({
    networks,
    projectId,
    transports: Object.values(widgetConfig).reduce<Record<number, ReturnType<typeof fallback>>>(
      (acc, curr) => {
        const httpProviders = (curr.rpcUrls as string[]).map((url) => http(url))
        acc[curr.id] = fallback(httpProviders)
        return acc
      },
      {},
    ),
  })

  const modalParams = {
    networks,
    projectId,
    adapters: [wagmiAdapter],
  }
  const modal = createAppKit(modalParams)

  return { modal, wagmiAdapter, modalParams }
}

Widget Implementation

import { QueryClient } from '@tanstack/react-query';
import { WagmiAdapter } from '@reown/appkit-adapter-wagmi'
import { MultisenderWidget } from '@multisender/react-widget';

import { widgetConfig, initAdapters } from './config'

const queryClient = new QueryClient();


const multisenderMantineTheme = createTheme({
  components: {
    Button: Button.extend({
      defaultProps: {
        opacity: 0.9,
      },
    }),
  },
})

function App() {
  const { wagmiAdapter } = initAdapters()

  return (
    <WagmiProvider config={wagmiAdapter.wagmiConfig}>
      <QueryClientProvider client={queryClient}>
        <MultisenderWidget
          config={widgetConfig}
          posthogKey='your-posthog-key'
          posthogHost="https://your-posthog-url.com"
          mantineTheme={multisenderMantineTheme} // Optional Mantine theme overrides
          classNames={{
            theme: 'custom-theme-class',
            mantineProvider: 'custom-mantine-provider-class',
          }} // Optional custom CSS classes
        />
      </QueryClientProvider>
    </WagmiProvider>
  );
}

Props

| Prop | Type | Required | Description | |----------------------|------------------------------------------------|----------|-------------------------------------------------------| | config | Record<number, ChainConfig> | Yes | multisender widget config | | wagmiConfig | Config | Yes | wagmi configuration (must match AppKit) | | queryClient | QueryClient | Yes | React Query client | | posthogKey | string | No | PostHog analytics key | | posthogHost | string | No | PostHog host URL | | theme | MultisenderThemeProp | No | Custom widget theme | | mantineTheme | MantineTheme | No | Mantine theme overrides | | mantineProviderProps | MantineProviderProps | No | Additional MantineProvider props | | classNames | { theme?: string; mantineProvider?: string } | No | Custom CSS classes | | logoType | LogoType | No | Variations of the Multisender.app Logo Implementation |

LogoType

type LogoType = 'default' | 'minified'

The default logo refers to the full-size version displayed in the top-left corner of the widget

The minified logo is a compact text element ("Powered by Multisender.app") accompanied by a small, minimized icon, positioned in the bottom-right corner of the widget

ChainConfig

type ChainConfig = {
  id: number // Chain Id
  name: string // Chain Name
  rpcUrls: string[] // List of RPC urls for viem Fallback Provider
  blockScoutApiUrl: string // BlockScout API url for fetching users data
  // This parameter is used to explicitly enforce a specific gas fee model.
  // For example, although BSC (chain ID 56) supports EIP-1559, we may want to use the 
  // legacy gas model instead, so we set `isSupportEstimateFees: false`.
  isSupportEstimateFees?: boolean
  optimisticVersion?: OptimisticVersions // Optimistic version 'ecotone' / 'fjord'
  blockExplorerUrl: {
    tx: string // 'https://eth.blockscout.com/tx/'
    address: string // 'https://eth.blockscout.com/address/'
  }
}

Posthog (posthogKey, posthogHost)

This parameters needs to be requested from the Multisender.app team.

Multisender theme prop

Minimal set of brand-specific properties

import { MultisenderThemeProp } from 'containers/Theme'

const multisenderTheme: MultisenderThemeProp = {
  color: {
    brand: 'red',
  },
}

export const YourApp: FC = () => (
  <WagmiProvider config={wagmiAdapter.wagmiConfig}>
    <QueryClientProvider client={queryClient}>
      <MultisenderWidget theme={multisenderTheme} config={config} />
    </QueryClientProvider>
  </WagmiProvider>
)

This will change Multisender brand color to 'red', painting buttons, radio buttons, some icons, and so on.

Mantine theme prop

You can add some of Mantine theme overrides

import { Button } from '@mantine/core'

const multisenderMantineTheme = createTheme({
  components: {
    Button: Button.extend({
      defaultProps: {
        opacity: 0.9,
      },
    }),
  },
})

export const YourApp: FC = () => (
  <WagmiProvider config={wagmiAdapter.wagmiConfig}>
    <QueryClientProvider client={queryClient}>
      <MultisenderWidget 
        mantineTheme={multisenderMantineTheme} 
        config={config} 
      />
    </QueryClientProvider>
  </WagmiProvider>
)

This will add opacity={0.9} prop to every <Button> used by Multisender or Mantine other components

NOTE: By default, withCssVariables if turned off for <MantineProvider>, so any CSS-generating props of Mantine theme will not work.

For example, you want to apply a theme with font setting:

const mantineTheme = createTheme({
  fontFamily: 'monospace',
})

But this prop will try to generate CSS and add it to new <style> element inside Mantine Provider component. This styles is not wrapped into @layer, so they cancel some Multisender theme overrides.

You can still turn it on to apply your own theme overrides using mantineProviderProps:


export const YourApp: FC = () => (
  <WagmiProvider config={wagmiAdapter.wagmiConfig}>
    <QueryClientProvider client={queryClient}>
      <MultisenderWidget
        mantineTheme={multisenderMantineTheme}
        mantineProviderProps={{ withCssVariables: true }}
        config={config}
      />
    </QueryClientProvider>
  </WagmiProvider>
)

You can override any MantineProvider props.

classNames prop

You can add your own CSS classes for Multisender widget wrapper elements to override CSS Custom Properties:

import styles from 'app.module.css'

export const YourApp: FC = () => (
  <WagmiProvider config={wagmiAdapter.wagmiConfig}>
    <QueryClientProvider client={queryClient}>
      <MultisenderWidget
        classNames={{
          theme: styles.multisenderTheme,
          mantineProvider: styles.multisenderMantineProvider,
        }}
        config={config}
      />
    </QueryClientProvider>
  </WagmiProvider>
)

app.module.css:

.multisenderTheme {
    /* Here you can override Multisender CSS Custom Properties, same as using 'theme' prop in <MultisenderWidget> */
    --mw-color-brand: red;
}

.multisenderMantineProvider {
    /* Here you can override Mantine CSS Custom Properties */
    --mantine-color-green-outline: darkgreen;
}

CSS Layers

If your app applies any global styles, place them into @layer global {} to avoid unexpected CSS specifity overloads.

For example, you have this CSS:

* { margin: 0; padding: 0 }

All CSS used by Multisender widget is wrapped into layers, so this style will cancel any margin or padding in widget components.

You can tune your global styles to resolve any problems you see, but Multisender widget has a lot of components and states, so you can miss some regressions.

Instead, wrap these global styles into a CSS layer:

@layer global {
    * { margin: 0; padding: 0 }
}

This will force browser to set this style specifity to lower value than Multisender widget CSS specifity.

Multisender widget CSS is placed into layers in this order:

  1. global – Empty layer you can use for global styles
  2. reset – The same, but named to match some other existing apps
  3. multisender-mantine-provider – Mantine Theme Provider styles
  4. multisender – Multisender widget styles
  5. mantine – Mantine styles

Lower the layer, less specifity.

You cannot change the order of this layers in your app.

Global styles

Probably, you want to apply some CSS reset in your app.

In Mantine widget, there is no global styles are applied. If want any, import them on host app.

We recommend normalize.css from CSS Tools:

import '@csstools/normalize.css'
import '@csstools/normalize.css/opinionated.css'

Dependencies

Ensure your project includes these dependencies:

{
  "dependencies": {
    "viem": "^2.30.0",
    "wagmi": "^2.15.4",
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
    "@reown/appkit": "^1.6.7",
    "@tanstack/react-query": "^5.67.1",
    "@reown/appkit-adapter-wagmi": "^1.6.7"
  }
}