A JavaScript Voting Dapp, based on IPFS, IOTA, and the Web Crypto API

Since the exact definition of a decentralized application (Dapp) is still debatable, let’s simply assume in this article that a Dapp is an application run on a decentralized network without any centralized part like a regular backend. Dapps have numerous advantages (e.g., security by design), but currently, most of the time they have three mandatory requirements, that make them uninteresting for most people:

  1. Installation of additional software
  2. Complicated sign-up process
  3. Necessary transaction fees

On top of it, the typical Dapps are quite expansive to run.

In this tutorial, we show how to create a simple voting application called DVote, which can be hosted completely for free on IPFS and doesn’t require any sign-up process or installation. We achieve this by running almost everything in the browser and only using the distributed ledger technology where it makes sense. DVote uses IOTA, the Web Crypto API, and IPFS. The idea is based on the following popular Ethereum Dapp Tutorial. The purpose of this application is to give you an idea of what is possible with this technology, so it’s not a finished product. For example, to make this really useful you would need to show the load progress (currently you just have to wait) as well as a simple login system, which prevents people from voting multiple times. You can find the full open source code on GitHub.

1. Get started

First, we need to set up our development environment. Make sure you have Node.js and NPM installed. Then run the following commands and answer the questions.

npm init
npm i -D webpack webpack-cli mini-css-extract-plugin css-loader html-webpack-plugin html-webpack-inline-source-plugin

Now you can add the following webpack.config.js to your project:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

const minifySettings = {
collapseWhitespace: true,
minifyCSS: true,
minifyJS: true,
minifyURLs: true,
removeComments: true,
removeEmptyAttributes: true,
removeOptionalTags: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
useShortDoctype: true,

module.exports = {
mode: 'production',
entry: {
index: './src/js/app.js',
output: {
filename: '[name].bundle.js',
publicPath: '',
path: path.resolve(__dirname, 'dist'),
plugins: [
new HtmlWebpackPlugin({
title: 'Dweb.page',
minify: minifySettings,
filename: './html/dvote.html',
template: './src/html/dvote.html',
chunks: ['index'],
inlineSource: '.(js|css)$',
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css',
new HtmlWebpackInlineSourcePlugin(),
module: {
rules: [
test: /.css$/,
use: [
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../',

Webpack helps us to create one single HTML file, which contains the complete source code of our application. This way the app can very easily be upload and distribute on IPFS. To start not from scratch, we use the open source project Versus and put everything unzipped inside the src folder. However, we need to change this project a little bit for our purpose.


The HTML file is our default template for the application. Therefore, we combine both HTML files into one file by copying the whole <div class=”survey-wrapper”> of the output.html into the index.html. We use JavaScript below to display only one part of the application based on the URL.

Additionally, we need to remove all the JavaScript and CSS-imports from the HTML document as well as add some new identifiers. It’s important also to change the old identifiers of the output.html, so you don’t have the same identifier twice in one HTML document. Feel free to also edit the default text or document layout at this stage. For example, we decided to change the previous host input field to show the random IOTA address which we will later use. Therefore, we also make the input field read-only (readonly=”readonly”). Finally, we rename the index.html to dvote.html, just to improve the searchability of this file on the distributed web.

You can find our final HTML file here.

3. CSS

Since Webpack now takes care of our CSS import, we need to add the CSS import to the app.js like below and remove it from every CSS file:

import ‘../css/input.css’;
import ‘../css/main.css’;
import ‘../css/output.css’;
import ‘../css/style.css’;

We also remove the background parts inside the form-wrapper of the input.css and add the following line to the body inside the main.css.

background: linear-gradient(135deg, #2a99ef 20%, #52d9e5 80%);

This way we don’t have to upload an additional background image on IPFS, which should improve the loading time of the application. If you want, you can now remove the image folder since we don’t need it anymore. We also make the previous host input field grey, since its now read-only (see above) and make additional small changes. For example, we change the text alignment of the survey title and info to center (text-align: center;), but overall feel free to get creative here.

Read the Full Article

This post was originally published on https://medium.com/@davidhawig?source=rss-5fe0790325f2——2. The IOTA-News Community curates, examines, and summarizes news from external services while producing its own original material. Copyrights from external sources will be credited as they pertain to their corresponding owners. The purpose is to make use of 3rd party content or pictures as either allusion or promotional endorsement of mentioned sites. If you have a claim of copyright infringement with respect to material, please mail to support[at]iota-news.com. IOTA-News.com is a community run website and is NOT affiliated with the IOTA Foundation in any way.