Skip to main content

DApp UI

This section presents how to create and setup a DApp's User Interface (UI) project using React and Beacon's DApp/wallet interaction.

Technical stack

App Framework

Any framework is suitable to create a DApp application as long as a Tezos library is available for it. We present here how to create a web DApp with React.

The choice of the React framework depends on the objective and the size of the application; typically a framework like Next.js is suited for large applications with needs for server side rendering. We are choosing create-react-app for its simplicity to create simple client-side & single-page applications: it installs and configures the whole pack of required bricks (webpack, babel, ...)

Language

It is strongly recommended to use TypeScript language as it will greatly shorten and ease up the development cycle. Its typed aspect makes that many errors are detected at compilation time (ie. at the time of writing code) rather than later at execution. It just doesn't make sense to developp with untyped languages when you think of it ...

Project templates configured with TypeScript are available with most UI frameworks. The following command uses create-react-app template with TypeScript:

npx create-react-app my-dapp --template TypeScript

This creates the my-dapp project. More information may be found here

Tezos library

While it is always possible to interact directly with the Tezos endpoint's RPC API, it is more than recommended to use a dedicated library that will wrap all services in high-level development services and take care of all the low-level Tezos protocol details.

In the context of web DApps for Tezos, the main library is Taquito:

npm install @taquito/taquito

Taquito uses official cryptographic packages (aka libraries). Some of these packages relies on nodejs packages designed to run on the back-end side (server side, not in a browser). These packages are crypto, stream, assert, http, https, os. As a result, the default build process fails; it is then necessary to map these packages to their front-end counterparts in the build process:

info

Follow instructions available here to solve build issues.

As a comment, create-react-app uses webpack (version 5) to bundle all resources as static web assets. It is then necessary to use the react-app-rewired package as described in instructions above, to be able to provide a customized webpack configuration without ejecting the react app.

Wallets

A DApp needs to interact with a wallet to sign operations (transfers, calls to a smart contract, ...). Many wallets are available on Tezos (Temple, Kukai, Umami, ...). It is common practice to interact with them all via Beacon that implements the interaction standard TZIP-10 between a wallet and a dApp, as it greatly reduces the integration effort with wallets.

npm install @taquito/beacon-wallet @airgap/beacon-sdk

The main drawback of Beacon is the lack of control over the UI elements (typically the wallet selection popup), which can be a no-go if you want a tight control of the DApp L&F. In that case, each wallet needs to be integrated separately.

A plug-and-play constate context for Beacon services connect and disconnect is available here.

Contract binding

When interacting with a contract (read and write), it is strongly recommended to use its generated TypeScript binding, that is a typed high-level TypeScript interface. It greatly reduces the effort to call a contract, read its storage and the number of runtime errors, as the compilier and LSP guides you through the contract interface.

TypeScript bindings may be obtained with the following Completium CLI command:

completium-cli generate binding-dapp-ts mycontract.arl > mycontract.ts
info

Bindings generation is also available for Michelson (.tz) files.

The generated binding interface relies on two packages:

npm install @completium/dapp-ts @completium/archetype-ts-types

Contexts

With React applications, it is strongly recommended to setup contexts for application data (settings, UI states, ...) in read/write modes with a dedicated package like constate or redux. This is preventing from awkward spaghetti code of passing components states and data through large hierarchy of components.

The DApp example presented here is using constate for its lightweight aspect.

npm install constate

Taquito and Beacon must be singletons, hence there are wrapped as contexts (with constate) to make them available to UI components. The same stands for the contract bindings.

The main 4 blockchain-related contexts are provided as plug-and-play code:

Contexts


Blockchain-related DApp settings


Provides Taquito's Tezos Toolkit hook


Beacon's connect connect and wallet address services


Provides contract binder

Architecture

Schema below illustrates the module and package architecture of the DApp and their interactions:

Buld DAppBuld DApp
  • Changes in Contexts data automatically redraw UI components that use them (React + constate hook mecanism)
  • Contexts and UI interact with contract via Binding
  • Contexts uses Beacon's services to connect to a wallet
  • Taquito's Tezos toolkit uses Beacon as transaction signer
  • Binding uses @completium/dapp-ts package services to interact with blockchain
  • @completium/dapp-ts uses @completium/event-listener to listen to emitted events

File structure

The typical file structure of the react project is presented below:

├── README.md
├── config-overrides.js
├── package.json
├── tsconfig.json
├── public
├── favicon.ico
├── index.html
├── manifest.json
└── robots.txt
└── src
├── App.css
├── App.test.tsx
├── App.tsx
├── index.css
├── index.tsx
├── react-app-env.d.ts
├── reportWebVitals.ts
├── setupTests.ts
├── bindings
└── ...
├── components
└── ...
├── routes
└── ...
└── contexts
├── Beacon.tsx
├── Taquito.tsx
├── Contract.tsx
├── Settings.tsx
└── ...

Note that 4 directories are created under src:

  1. bindings: generated contracts bindings
  2. routes: page UI components managed by a route manager (for example react-router-dom)
  3. components: other UI components
  4. contexts: hooks providers