# How to integrate a decentralized application (dApp) (https://docs-orhepa2tm-ton-core-docs.vercel.app/llms/ecosystem/ton-connect/dapp/content.md)



This guide helps you integrate your dApp with TON or build one from scratch using [TON Connect](/llms/ecosystem/ton-connect/overview/content.md) and auxiliary libraries.

TON Connect is a standard wallet connection protocol in TON. It consists of supplementary SDKs and supervises two major use cases: dApps integrations with TON and custom wallet integrations.

To proceed with a dApp integration, select your framework or environment:

<Columns cols="3">
  <Card icon="react" title="React" href="#react" />

  <Card icon="square-n" title="Next.js" href="#next-js" />

  <Card icon="js" title="Vanilla JS" href="#vanilla-js" />
</Columns>

## Integration [#integration]

### React [#react]

<Steps>
  <Step>
    #### Install necessary libraries [#install-necessary-libraries]

    Install the `@tonconnect/ui-react` package:

    ```shell
    npm i @tonconnect/ui-react
    ```

    That is enough for the most basic usage. However, to allow for more complex examples, install the following packages as well:

    ```shell
    npm i @ton-community/assets-sdk @ton/ton @ton/core
    ```
  </Step>

  <Step>
    #### Create a TON Connect manifest [#create-a-ton-connect-manifest]

    [TON Connect manifest](/llms/ecosystem/ton-connect/manifest/content.md) is a small JSON file that lets wallets discover information about your dApp. It should be named `tonconnect-manifest.json`, placed at `https://<YOUR_APP_URL>/tonconnect-manifest.json`, and be accessible with a direct GET request.

    <Callout>
      Notice that [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS) should be disabled, and there should be no authorization or intermediate proxies like CloudFlare or similar services. The connection also won’t work when using a VPN.
    </Callout>

    Here's an example of such a file:

    ```json title="tonconnect-manifest.json"
    {
      "url": "https://tonconnect-sdk-demo-dapp.vercel.app/",
      "name": "Demo Dapp with React UI",
      "iconUrl": "https://tonconnect-sdk-demo-dapp.vercel.app/apple-touch-icon.png",
      "termsOfUseUrl": "https://tonconnect-sdk-demo-dapp.vercel.app/terms-of-use.txt",
      "privacyPolicyUrl": "https://tonconnect-sdk-demo-dapp.vercel.app/privacy-policy.txt"
    }
    ```

    After creating the manifest file, import `TonConnectUIProvider` to the root of your dApp and pass the manifest URL:

    ```tsx
    import { TonConnectUIProvider } from '@tonconnect/ui-react';

    export function App() {
      return (
        <TonConnectUIProvider
          manifestUrl="https://<YOUR_APP_URL>/tonconnect-manifest.json"
        >
          { /* Your app */ }
        </TonConnectUIProvider>
      );
    }
    ```

    See more detailed information here: [TON Connect manifest](/llms/ecosystem/ton-connect/manifest/content.md).
  </Step>

  <Step>
    #### Add a button in the UI [#add-a-button-in-the-ui]

    Users need a clear way of connecting their wallets to your app, so you must give a clear UI element to do so. Usually, that is a <kbd>Connect wallet</kbd> button.

    Some in-wallet browsers automatically open a wallet connection modal when your dApp loads. Still, always provide a button alternative in case the user dismissed the modal window or wants to connect a wallet after doing their research.

    Adding `TonConnectButton` is straightforward:

    ```tsx
    import { TonConnectButton } from '@tonconnect/ui-react';

    export const Header = () => {
      return (
        <header>
          <span>My App with React UI</span>
          <TonConnectButton />
        </header>
      );
    };
    ```

    The `TonConnectButton` is a universal UI component for initializing a connection. After the wallet is connected, it transforms into a wallet menu. Prefer to place the <kbd>Connect wallet</kbd> button in the top right corner of your app.

    You can add the `className` and style props to the button:

    ```jsx
    <TonConnectButton className="my-button-class" style={{ float: "right" }}/>
    ```

    <Callout type="caution">
      You cannot pass a child element to the `TonConnectButton`.
    </Callout>
  </Step>

  <Step>
    #### Utilize TON Connect in your dApp [#utilize-ton-connect-in-your-dapp]

    <Card title="Common usage recipes" href="#usage" />
  </Step>
</Steps>

#### Manual connection initiation [#manual-connection-initiation]

You can always initiate the connection manually using the `useTonConnectUI` hook and [openModal](https://github.com/ton-connect/sdk/tree/main/packages/ui#open-connect-modal) method.

```tsx
import { useTonConnectUI } from '@tonconnect/ui-react';

export const Header = () => {
  const [tonConnectUI, setOptions] = useTonConnectUI();
  return (
    <header>
      <span>My App with React UI</span>
      <button onClick={() => tonConnectUI.openModal()}>
        Connect Wallet
      </button>
    </header>
  );
};
```

To open a modal window for a specific wallet, use the `openSingleWalletModal()` method. It takes the wallet's `app_name` and opens the corresponding wallet modal, returning a promise that resolves once the modal window opens.

To find the correct `app_name` of the target wallet, refer to the [wallets-list.json](https://github.com/ton-blockchain/wallets-list/blob/main/wallets-v2.json) file.

```tsx
<button onClick={() => tonConnectUI.openSingleWalletModal('tonwallet')}>
  Connect Wallet
</button>
```

#### UI customization [#ui-customization]

To customize the UI of the modal, use the `tonConnectUI` object provided by the `useTonConnectUI()` hook, and then assign designated values as an object to the `uiOptions` property.

```tsx
// Somewhere early in the component:
const [tonConnectUI] = useTonConnectUI();

// ...

// Somewhere later in the same component:
tonConnectUI.uiOptions = {
  language: 'ru', // sets the target language
  uiPreferences: {
    theme: THEME.DARK, // dark theme of the modal
  }
};
```

In the object assigned, you should only pass options that you want to change — they will be merged with the current UI options. UI element will be re-rendered after such assignment.

<Callout type="caution">
  Note that you have to pass an object and never set individual sub-properties under `uiOptions`. That is, **DO NOT** do this:

  ```tsx
  /* WRONG, WILL NOT WORK */
  tonConnectUI.uiOptions.language = 'ru';
  ```
</Callout>

See all available `uiOptions` in the external reference: [`TonConnectUiOptions` Interface](https://ton-connect.github.io/sdk/interfaces/_tonconnect_ui.TonConnectUiOptions.html).

#### Minimal React setup [#minimal-react-setup]

Putting all the above together, here's a most minimal React dApp integration example.

First, start by creating a new project with React and Vite:

```shell
npm create vite@latest demo-react-dapp -- --template react-ts
```

Then, go into the project and add the `@tonconnect/ui-react` dependency:

```shell
cd demo-react-dapp
npm i @tonconnect/ui-react # this will also install other missing dependencies
```

Edit your `App.tsx` to have the following imports present:

```tsx title="src/App.tsx"
import {
  TonConnectUIProvider,
  TonConnectButton,
  useTonConnectUI,
  useTonWallet,
  CHAIN,
} from '@tonconnect/ui-react';
```

Finally, in the same `App.tsx` file, replace your `App()` function with the following:

```tsx title="src/App.tsx" expandable
function App() {
  const [tonConnectUI] = useTonConnectUI();
  const wallet = useTonWallet();

  const sendToncoin = async (amount: string) => {
    if (!wallet) return;

    // Once the user has connected,
    // you can prepare and send a message from the wallet:
    try {
      await tonConnectUI.sendTransaction({
        validUntil: Math.floor(Date.now() / 1000) + 300,
        network: CHAIN.TESTNET,
        messages: [{ address: wallet.account.address, amount }],
      });
    }
  };

  return (
    <TonConnectUIProvider
      {/*
        We re-use an existing manifest here. To specify your own while developing locally,
        setup a tunnel and an https domain with the help of ngrok or similar tools.
      */}
      manifestUrl="https://tonconnect-sdk-demo-dapp.vercel.app/tonconnect-manifest.json"
    >
      <TonConnectButton />
      <button
        {/*
          Notice that it is important to specify Toncoin in nanoToncoin format,
          where 1 Toncoin is equal to 10⁹ nanoToncoin:
        */}
        onClick={() => sendToncoin(String(100_000_000))}
      >
        Send 0.1 TON
      </button>
    </TonConnectUIProvider>
  );
}
```

Now, execute `npm run dev` to launch and preview your app in the browser at `http://localhost:5173`. All changes in code will be reflected live.

Connect a wallet and try using the <kbd>Send 0.1 TON</kbd> button. Notice that the exact sum of Toncoin shown in your wallet **will be different**, because there are certain fees required for such a transfer by the blockchain itself.

When building apps, make sure to **always take fees into consideration** and show them to the end-user.

<Callout type="caution">
  This example sends **real TON** from the connected wallet. Try it with a testnet wallet first or send less Toncoin, e.g., 0.001 TON instead of 1 TON, to avoid surprises.
</Callout>

### Next.js [#nextjs]

`TonConnectUIProvider` relies on browser APIs and should be rendered only on the client side, i.e., on the frontend. As such, in a Next.js application, you should mark the component that wraps the provider with [`'use client'` directive](https://nextjs.org/docs/app/api-reference/directives/use-client).

Alternatively, dynamically import the provider to disable server-side rendering.

Both approaches ensure that the provider is invoked only in the browser and works correctly there.

Example for the `app` router:

```tsx title="app/providers.tsx"
'use client';

import { TonConnectUIProvider } from '@tonconnect/ui-react';

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <TonConnectUIProvider
      manifestUrl="https://<YOUR_APP_URL>/tonconnect-manifest.json"
    >
      {children}
    </TonConnectUIProvider>
  );
}
```

For the `pages` router, you can dynamically import the provider:

```tsx
import dynamic from 'next/dynamic';

const TonConnectUIProvider = dynamic(
  () => import('@tonconnect/ui-react').then(m => m.TonConnectUIProvider),
  { ssr: false }
);

function MyApp({ Component, pageProps }) {
  return (
    <TonConnectUIProvider
      manifestUrl="https://<YOUR_APP_URL>/tonconnect-manifest.json"
    >
      <Component {...pageProps} />
    </TonConnectUIProvider>
  );
}
```

### Vanilla JS [#vanilla-js]

For quick testing, use the following single-file HTML example.

<Callout type="caution">
  This example sends **real Toncoin** from the connected wallet. Try it with a testnet wallet first or send less Toncoin, e.g., 0.001 TON instead of 1, to avoid surprises.
</Callout>

```html title="index.html" expandable
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>TON Connect sandbox</title>
  <script src="https://unpkg.com/@tonconnect/ui@latest/dist/tonconnect-ui.min.js"></script>
</head>
<body>
  <div id="ton-connect"></div>
  <button id="send" disabled>Send 0.1 TON</button>
  <script>
    const ui = new TON_CONNECT_UI.TonConnectUI({
      // Let's re-use the manifest from the demo app
      manifestUrl: 'https://tonconnect-sdk-demo-dapp.vercel.app/tonconnect-manifest.json',
      buttonRootId: 'ton-connect', // anchor id with the element to hook the "Connect wallet" button onto
    });
    ui.onStatusChange(w => document.getElementById('send').disabled = !w);
    document.getElementById('send').onclick = async () => {
      // This will send 0.1 Toncoin from the connected wallet, beware!
      try {
        await ui.sendTransaction({
          validUntil: Math.floor(Date.now()/1000) + 300,
          messages: [{ address: ui.account.address, amount: String(100_000_000) }],
        });
      }
    };
  </script>
</body>
</html>
```

## See also [#see-also]

* [TON Connect overview](/llms/ecosystem/ton-connect/overview/content.md)
* [TON Connect manifests](/llms/ecosystem/ton-connect/manifest/content.md)
* [Integrate a wallet](/llms/ecosystem/ton-connect/wallet/content.md)
* [WalletKit overview](/llms/ecosystem/walletkit/overview/content.md)
