Skip to main content
info

Please note that zkApp programmability is not yet available on Mina Mainnet, but zkApps can now be deployed to Berkeley Testnet.

How to Write a zkApp UI

Learn how to write an UI for your smart contract

To allow users to interact with your smart contract, you’ll typically want to build a website UI.

This UI can be written with any framework (e.g. React, Vue, Svelte, etc.) or plain HTML and JavaScript.

note

This page is a work in progress.

Adding your smart contract as a dependency of the UI

Setup

The index.ts file is the entry point of your project. This file only imports all smart contract classes you want access to, and exports them. This pattern allows you to specify which smart contracts are available to import when consuming your project from npm within your UI.

import { YourSmartContract } from "./YourSmartContract.js";

export { YourSmartContract };

Local development

The npm link command allows to use your smart contract within your UI project during local development without needing to publish it npm. This allows for rapid development.

  1. Using a command line, change into your smart contract project directory using cd <your-project>, type npm link, and hit enter.
  2. Using a command line, change into your UI project directory using cd <your-ui-project>, type npm link <your-package-name>, and hit enter. your-package-name is the name property used within your smart contract's package.json.
  3. Import into your UI project like normal, using import { YourSmartContract } from ‘your-package-name’;.

Remember to run npm run build in your smart contract directory after making any changes in order for changes to be reflected in the smart contract consumed by your UI project.

tip

For additional details about npm link, see the full npm reference docs.

Publish to npm for production

  1. Create an npm account: Create one here if you don't have one yet.
  2. Login: To sign in, enter npm login on the command line. You will be prompted to enter your username, password, and email address.
  3. Publish: To publish your package, enter npm publish on the command line at the root of your smart contract project directory. If the package name already exists on npm, you will get an error. You can change the package name by changing the name property in your package.json.
tip

You can check if a package name already exists on npm using the npm search terminal command. To avoid naming collisions, npm allows to publish scoped packages: @your-username/your-package-name. For additional details about publishing packages including scoped packages, see the full npm reference docs.

Consuming your smart contract in your UI

Once you have published your smart contract to npm, you can easily add it to any UI framework of your choosing by importing the package.

  1. Install your smart contract package: To install your package, run the following npm command: npm install your-package-name from the root of your UI project directory. Or if you published a scoped npm package, run npm install @your-username/your-project-name.
  2. Import your smart contract package into the UI using: import { YourSmartContract } from ‘your-package-name’; , where YourSmartContract is the named export that you chose in your smart contract.
tip

For a more performant UI, you may want to render your UI before importing and loading your smart contract. This allows the SnarkyJS wasm workers to perform initialization without blocking the UI.

For example, if your UI is built using React, loading the smart contract in a useEffect, instead of a top level import, will give the UI time to render its components before loading SnarkyJS.

Loading your contract with React

useEffect(() => {
(async () => {
const { YourSmartContract } = await import("your-package-name");
})();
}, []);

Loading your contract with Svelte

onMount(async () => {
const { YourSmartContract } = await import("your-package-name");
});

Loading your contract with Vue

onMounted(async () => {
const { YourSmartContract } = await import("your-package-name");
});

Enabling COOP and COEP headers

To load SnarkyJS code in your UI, you must set the COOP and COEP headers as described below. These enable SnarkyJS' use of SharedArrayBuffer, which SnarkyJS relies on to enable important WebAssembly features.

  • Cross-Origin-Opener-Policy must be set to same-origin.
  • Cross-Origin-Embedder-Policy must be set to require-corp.

You can enable these headers a number of different ways. If you deploy your UI to a host such as Vercel or Cloudflare Pages, you can set these headers in a custom configuration file (see below). Otherwise, you can set these headers in the server framework of your choice (e.g. Express for JavaScript).

Vercel

If your app will be hosted on Vercel, you can set these headers via vercel.json.

{
"headers": [
{
"source": "/(.*)",
"headers": [
{ "key": "Cross-Origin-Opener-Policy", "value": "same-origin" },
{ "key": "Cross-Origin-Embedder-Policy", "value": "require-corp" }
]
}
]
}

Cloudflare Pages

If your app will be hosted on Cloudflare Pages, you can set these headers via a _headers file.

/*
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp