> ## Documentation Index
> Fetch the complete documentation index at: https://docs.magic.link/llms.txt
> Use this file to discover all available pages before exploring further.

# Wallet Kit

> With Magic, you can use a pre-built React component that provides a complete authentication UI with support for email, OAuth, and external wallet login.

### Compatibility

The Wallet Kit widget requires React 18+ and is available for web applications using the [JavaScript SDK](/embedded-wallets/sdk/client-side/javascript).

## Use Cases

* Add a complete login UI to your React app without building custom components
* Support multiple authentication methods (email OTP, OAuth, Farcaster, external wallets) from a single widget

## Getting Started

### Installation

<CodeGroup>
  ```bash NPM icon="npm" theme={null}
  npm install magic-sdk @magic-ext/wallet-kit
  ```

  ```bash Yarn icon="yarn" theme={null}
  yarn add magic-sdk @magic-ext/wallet-kit
  ```
</CodeGroup>

### Usage

Initialize Magic with the `WalletKitExtension`, then render the `MagicWidget` component in your app.

```jsx JavaScript icon="square-js" theme={null}
import { Magic } from 'magic-sdk';
import { MagicWidget, WalletKitExtension } from '@magic-ext/wallet-kit';

const magic = new Magic('YOUR_API_KEY', {
  extensions: [new WalletKitExtension()],
});

export default function LoginPage() {
  const handleSuccess = (result) => {
    switch (result.method) {
      case 'email':
        // result.didToken for backend verification
        console.log('Email login:', result.didToken);
        break;
      case 'oauth':
        // result.magic.idToken for backend verification
        console.log('OAuth login:', result.magic.idToken);
        break;
      case 'farcaster':
        // result.didToken for backend verification
        console.log('Farcaster login:', result.didToken, result.farcaster);
        break;
      case 'wallet':
        // result.walletAddress for wallet connections
        console.log('Wallet connected:', result.walletAddress);
        break;
    }
  };

  return (
    <MagicWidget
      wallets={['metamask', 'coinbase', 'walletconnect']}
      enableFarcaster
      onSuccess={handleSuccess}
      onError={(error) => console.error(error)}
    />
  );
}
```

### Configuration

The widget displays login options based on two sources:

**Dashboard-configured options** — Email OTP and OAuth providers (Google, Apple, GitHub, etc.) are configured in your [Magic Dashboard](https://dashboard.magic.link). Enable the authentication methods you want, and they will automatically appear in the widget.

**Code-configured options** — External wallets and Farcaster are configured via props. Pass `wallets` to specify which external wallets to display, and `enableFarcaster` to show a Farcaster login button.

For example, if you enable Email and Google OAuth in your dashboard and pass `wallets={['metamask']}` and `enableFarcaster`, the widget will show all four options: email input, Google sign-in button, Farcaster, and MetaMask.

### Farcaster

To enable Farcaster login, pass the `enableFarcaster` prop. This adds a Farcaster button alongside your OAuth social providers. When clicked, users see a QR code they can scan with the Warpcast app on their phone. On mobile devices, the widget automatically redirects to the Farcaster app.

```jsx JavaScript icon="square-js" theme={null}
<MagicWidget
  enableFarcaster
  onSuccess={(result) => {
    if (result.method === 'farcaster') {
      console.log('DID token:', result.didToken);
      console.log('Farcaster user:', result.farcaster.username);
    }
  }}
/>
```

### WalletConnect

If you include `'walletconnect'` in the `wallets` prop, the widget uses [Reown](https://reown.com/) (formerly WalletConnect) under the hood. A default project ID is included for development, but for production apps you should provide your own to avoid rate limiting:

```jsx JavaScript icon="square-js" theme={null}
const magic = new Magic('YOUR_API_KEY', {
  extensions: [new WalletKitExtension({ projectId: 'YOUR_REOWN_PROJECT_ID' })],
});
```

You can get a project ID by creating a free account at [dashboard.walletconnect.com](https://dashboard.walletconnect.com).

### Account Switching

When a user switches to a different account in their wallet (e.g. MetaMask), the widget automatically re-runs SIWE authentication for the new account in the background. The user will see their wallet's native signing prompt — no widget UI changes occur. Use `onAccountChanged` to respond when the new session is ready:

```jsx JavaScript icon="square-js" theme={null}
<MagicWidget
  wallets={['metamask']}
  onSuccess={(result) => {
    if (result.method === 'wallet') {
      setAddress(result.walletAddress);
    }
  }}
  onAccountChanged={(result) => {
    // New SIWE session is verified — safe to update your app state
    setAddress(result.walletAddress);
  }}
  onError={(error) => {
    // Fires for both initial login failures and account switch re-auth failures
    console.error(error);
  }}
/>
```

## API Reference

### Props

| Prop                  | Type                                  | Default    | Description                                                                                                                                                                                     |
| --------------------- | ------------------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `displayMode`         | `'inline' \| 'modal'`                 | `'inline'` | How the widget is displayed. `'inline'` renders in document flow, `'modal'` shows as an overlay.                                                                                                |
| `isOpen`              | `boolean`                             | `true`     | Whether the widget is visible.                                                                                                                                                                  |
| `onClose`             | `() => void`                          | —          | Called when the user closes the widget.                                                                                                                                                         |
| `closeOnSuccess`      | `boolean`                             | `false`    | Automatically close after successful login (shows success screen for 2 seconds first).                                                                                                          |
| `closeOnClickOutside` | `boolean`                             | `false`    | Close when clicking the backdrop. Only applies in modal mode.                                                                                                                                   |
| `wallets`             | `Array`                               | `[]`       | External wallets to display: `'metamask'`, `'coinbase'`, `'phantom'`, `'rabby'`, `'walletconnect'`.                                                                                             |
| `enableFarcaster`     | `boolean`                             | `false`    | Show a Farcaster login button alongside social providers.                                                                                                                                       |
| `onSuccess`           | `(result: LoginResult) => void`       | —          | Called on successful login. See [Login Results](#login-results) for result structure.                                                                                                           |
| `onAccountChanged`    | `(result: WalletLoginResult) => void` | —          | Called when a wallet user switches to a different account and re-authentication completes. Fires after the new SIWE session is verified, so `result.walletAddress` reflects the active account. |
| `onError`             | `(error: Error) => void`              | —          | Called when login fails, or when a re-authentication triggered by an account switch fails (e.g. the user rejects the signing prompt).                                                           |
| `onReady`             | `() => void`                          | —          | Called when the widget has initialized and applied theme settings.                                                                                                                              |

### Login Results

The `onSuccess` callback receives a result object with a `method` property indicating the authentication type:

```typescript theme={null}
// Email OTP login
{ method: 'email', didToken: string }

// OAuth login (Google, Apple, etc.)
{ method: 'oauth', oauth: { provider, scope, userHandle, userInfo }, magic: { idToken, userMetadata } }

// Farcaster login
{ method: 'farcaster', didToken: string, farcaster: { fid?, username?, displayName?, pfpUrl?, bio? } }

// External wallet login
{ method: 'wallet', walletAddress: string }
```

For email and Farcaster logins, use `result.didToken` for backend verification. For OAuth logins, use `result.magic.idToken`. Farcaster logins also include the user's Farcaster profile data in `result.farcaster`.

## Examples

### Modal Mode

Use modal mode to display the widget as an overlay:

```jsx JavaScript icon="square-js" theme={null}
import { useState } from 'react';
import { MagicWidget } from '@magic-ext/wallet-kit';

function App() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <>
      <button onClick={() => setIsOpen(true)}>Log in</button>
      <MagicWidget
        displayMode="modal"
        isOpen={isOpen}
        onClose={() => setIsOpen(false)}
        closeOnClickOutside
        closeOnSuccess
        onSuccess={(result) => console.log(result)}
      />
    </>
  );
}
```

### Loading State

The widget fetches configuration from your Magic dashboard before rendering. During this time, it returns `null`. To show a loading indicator, render the widget with `isOpen={false}` and wait for `onReady`:

```jsx JavaScript icon="square-js" theme={null}
import { useState } from 'react';
import { Magic } from 'magic-sdk';
import { MagicWidget, WalletKitExtension } from '@magic-ext/wallet-kit';

// Create Magic instance once, outside the component
const magic = new Magic('YOUR_API_KEY', {
  extensions: [new WalletKitExtension()],
});

function LoginPage() {
  const [isLoading, setIsLoading] = useState(true);
  const [isOpen, setIsOpen] = useState(false);

  const handleReady = () => {
    setIsLoading(false);
    setIsOpen(true);
  };

  return (
    <>
      {isLoading && <div>Loading...</div>}
      <MagicWidget
        isOpen={isOpen}
        onReady={handleReady}
        onSuccess={(result) => console.log(result)}
      />
    </>
  );
}
```

<Note>
  Create the Magic instance outside your component or use `useMemo` to prevent recreating it on every render.
</Note>

## Theming

The widget automatically applies your Magic dashboard theme settings including colors and light/dark mode. Configure these in your [Magic Dashboard](https://dashboard.magic.link).

## Resources

* [JavaScript SDK](/embedded-wallets/sdk/client-side/javascript)
* [Email OTP Login](/embedded-wallets/authentication/login/email-otp)
* [OAuth Implementation](/embedded-wallets/authentication/login/oauth/implementation)
* [Farcaster Login](/embedded-wallets/authentication/login/farcaster)
