Guide: Integrate Blinks into your Client

This guide describes how you can get started integrating Blinks in your own client, such as a wallet, web3 social dApp, or other kind of site.

It covers both native integrations as well as injection via Chrome Extensions, and describes how developers may customize the styles for a Blink to get them on brand with the surrounding site.

It is meant for web3 clients such as

  1. Wallet chrome extensions that render Blinks on Twitter, like Phantom or Backpack.

  2. "Interstitial" or "Popup" sites like https://dial.to.

  3. Creating Blink "sheets" inside mobile wallets for more efficient signing.

  4. or other web3 dApps that want to bring Blinks to their platform, such as social dApps.

If you are looking for developer tools on how to build your first actions that will get delivered to clients by other providers, check out our Actions documentation.

Check out the Blinks SDK on github:

Installation

# npm
npm -i @dialectlabs/blinks

# yarn
yarn add @dialectlabs/blinks

This section covers adding Blinks directly to your dApp.

The following hooks are exported from @dialectlabs/blinks/react in order to simplify the integration.

  • useAction - overall hook: fetches the action, sets up an adapter, inits registry and refreshes it every 10 minutes

  • useActionsRegistry - fetches the registry and refreshes it

  • useActionAdapter - sets up an adapter for Action using wallet provider

If you want to build your own hooks, use Action , ActionsRegistry and ActionConfig/ActionAdapter classes and interfaces.

If you are using the useActionAdapter hook, then be sure to have<WalletProvider />and<WalletModalProvider /> above in the component tree.

Basic usage:

import '@dialectlabs/blinks/index.css';
import { useState, useEffect } from 'react';
import { Action, Blink, ActionsRegistry } from "@dialectlabs/blinks";
import { useAction } from '@dialectlabs/blinks/react';

// needs to be wrapped with <WalletProvider /> and <WalletModalProvider />
const App = () => {
    const [action, setAction] = useState<Action | null>(null);
    const actionApiUrl = '...';
    // useAction initiates registry, adapter and fetches the action.
    const { action } = useAction(actionApiUrl, { rpcUrlOrConnection: <YOUR_CONNECTION_OR_RPC> });    

    return action ? <Blink action={action} websiteText={new URL(actionApiUrl).hostname} /> : null;
}

Advanced:

import '@dialectlabs/blinks/index.css';
import { useState, useEffect } from 'react';
import { Action, Blink, ActionsRegistry, type ActionAdapter } from "@dialectlabs/blinks";
import { useAction, useActionsRegistryInterval } from '@dialectlabs/blinks/react';

// needs to be wrapped with <WalletProvider /> and <WalletModalProvider />
const App = () => {
    // SHOULD be the only instance running (since it's launching an interval)
    const { isRegistryLoaded } = useActionsRegistryInterval();
    const { adapter } = useActionAdapter(<YOUR_RPC_URL_OR_CONNECTION>);
    
    return isRegistryLoaded ? <ManyActions adapter={adapter} /> : null;
}

const ManyActions = ({ adapter }: { adapter: ActionAdapter }) => {
    const apiUrls = useMemo(() => (['...', '...', '...']), []);
    const [actions, setActions] = useState<Action[]>([]);
    
    useEffect(() => {
        const fetchActions = async () => {
            const promises = apiUrls.map(url => Action.fetch(url).catch(() => null));
            const actions = await Promise.all(promises);
            
            setActions(actions.filter(Boolean) as Action[]);
        }
        
        fetchActions();
    }, [apiUrls]);
    
    // we need to update the adapter every time, since it's dependent on wallet and walletModal states
    useEffect(() => {
        actions.forEach((action) => action.setAdapter(adapter));
    }, [actions, adapter]);
    
    return actions.map(action => (
        <div key={action.url} className="flex gap-2">
            <Blink action={action} websiteText={new URL(action.url).hostname} />
        </div>
    );
}

Dialect's Blinks SDK supports customizable styles so you can render Blinks that match the style of your dApp or 3rd party site, such as Twitter.

To render a Blink with a preset pass stylePreset prop (defaults to default which is the dial.to theme) to <Blink /> component:

import { Blink } from '@dialectlabs/blinks';
...
return <Blink stylePreset="x-dark" ... />;

Style presets are mapped to classes the following way:

  • x-dark -> .x-dark

  • x-light -> .x-light

  • default -> .dial-light

  • custom -> .custom

To override a certain preset use the following CSS Variables:

/* 
    Use .x-dark, .x-light, .dial-light, or .custom classes 
    .custom - does not contain any colors, radii or shadow
*/
.blink.x-dark {
    --blink-bg-primary: #202327;
    --blink-button: #1d9bf0;
    --blink-button-disabled: #2f3336;
    --blink-button-hover: #3087da;
    --blink-button-success: #00ae661a;
    --blink-icon-error: #ff6565;
    --blink-icon-error-hover: #ff7a7a;
    --blink-icon-primary: #6e767d;
    --blink-icon-primary-hover: #949ca4;
    --blink-icon-warning: #ffb545;
    --blink-icon-warning-hover: #ffc875;
    --blink-input-bg: #202327;
    --blink-input-stroke: #3d4144;
    --blink-input-stroke-disabled: #2f3336;
    --blink-input-stroke-error: #ff6565;
    --blink-input-stroke-hover: #6e767d;
    --blink-input-stroke-selected: #1d9bf0;
    --blink-stroke-error: #ff6565;
    --blink-stroke-primary: #1d9bf0;
    --blink-stroke-secondary: #3d4144;
    --blink-stroke-warning: #ffb545;
    --blink-text-brand: #35aeff;
    --blink-text-button: #ffffff;
    --blink-text-button-disabled: #768088;
    --blink-text-button-success: #12dc88;
    --blink-text-error: #ff6565;
    --blink-text-error-hover: #ff7a7a;
    --blink-text-input: #ffffff;
    --blink-text-input-disabled: #566470;
    --blink-text-input-placeholder: #6e767d;
    --blink-text-link: #6e767d;
    --blink-text-link-hover: #949ca4;
    --blink-text-primary: #ffffff;
    --blink-text-secondary: #949ca4;
    --blink-text-success: #12dc88;
    --blink-text-warning: #ffb545;
    --blink-text-warning-hover: #ffc875;
    --blink-transparent-error: #aa00001a;
    --blink-transparent-grey: #6e767d1a;
    --blink-transparent-warning: #a966001a;
    
    --blink-border-radius-rounded-lg: 0.25rem;
    --blink-border-radius-rounded-xl: 0.5rem;
    --blink-border-radius-rounded-2xl: 1.125rem;
    --blink-border-radius-rounded-button: 624.9375rem;
    --blink-border-radius-rounded-input: 624.9375rem;
    
    /* box-shadow */
    --blink-shadow-container: 0px 2px 8px 0px rgba(59, 176, 255, 0.22), 0px 1px 48px 0px rgba(29, 155, 240, 0.24);
}

Be sure to override with CSS Specificity in mind or by import order

This section is for Chrome extension developers who want to add Blinks to third party sites like Twitter.

// contentScript.ts
import { setupTwitterObserver } from "@dialectlabs/blinks/ext/twitter";
import { ActionConfig, ActionContext } from "@dialectlabs/blinks";

// your RPC_URL is used to create a connection to confirm the transaction after action execution
setupTwitterObserver(new ActionConfig(RPC_URL, {
  signTransaction: async (tx: string, context: ActionContext) => { ... },
  connect: async (context: ActionContext) => { ... }
}))

// or

import { type ActionAdapter } from "@dialectlabs/blinks";

class MyActionAdapter implements ActionAdapter {
  async signTransaction(tx: string, context: ActionContext) { ... }
  async connect(context: ActionContext) { ... }
  async confirmTransaction(sig: string, context: ActionContext) { ... }
}

setupTwitterObserver(new MyActionAdapter());

ActionContext contains the original url, executing Action instance, action type from the registry and the linked action, that initiated the method

If you are interested in adding Blinks, reach out to us on our Discord.

Last updated