Building HTML5 kiosk applications with Vue.js and Electron

Andreas Schallwig
8 min readAug 23, 2019

This guide assumes you already have at least basic knowledge about Vue.js and want to learn how to package your Apps with Electron. If you’re looking to get started with Vue.js I highly recommend the guide on their website as starting point.

If you have ever developed and deployed a browser based kiosk application you are probably familiar with some of the usual annoyances:

  • Browsers will display update reminders which is especially annoying for offline applications.
  • Improper shutdown of the browser (or operating system) will result in popup messages like “Chrome didn’t shutdown properly” on the next start.
  • Users will (intentionally or not) close the application window, rendering your kiosk useless — or even exposing data that should not be accessible.
  • Some well-meaning person updates the browser on your kiosk system causing the application to behave all weird.

Note: Don’t get me wrong — I perfectly understand these are all important browser security mechanisms. Just for kiosk applications they are usually not necessary and rather annoying.

“No matter how hard you try, your browser (and your users!) will try even harder to ruin your application and user experience.”

In a perfect (kiosk) world we’d have the ability to lock down our application to a point that users are restricted to the actions that we want them to perform. Also the browser would merely act as our canvas with exactly defined capabilities and doesn’t get into our way.

And this is why you want to use Electron!

Electron to the rescue

Electron is a framework to package your HTML5 / JavaScript based applications into a standalone desktop application for multiple platforms (Windows / MacOS / Linux).

It is however much more than just “WebPack for executables” but has a number of unique features which make it a great choice for kiosk applications (or any kind of desktop application that is):

  • Electron applications package Chromium as rendering engine, eliminating all of the issues described above. You deliver your application package with the browser engine included.
  • Due to the included browser engine you also eliminate all kinds of JavaScript / CSS cross-browser issues as you develop for an exactly defined browser environment. No more “breaks in production”!
  • Electron also natively integrates with NodeJS modules, providing you with useful libraries for networking or file system access — or anything else you have previously used NodeJS for.
  • You have direct access not only to the Chromium rendering engine but also to the Application itself. This will allow you to establish some additional lockdown measures or deal with unintended application shutdown.

Let’s look at how to install and use it:

Getting your environment ready

The easiest way to create a new Vue.js application is using the vue-cli tool. Go ahead and install it via:

npm install -g @vue/cli

You can now create your new application by typing:

vue create my-app

The installer will ask you which modules you wish to include with your new application. For your first app I recommend the following settings:

  • Choose “Manually select features”
  • Enable “Babel” (it should be selected by default)
  • Enable “Router”
  • Enable “CSS Pre-processors”
  • Enable “Linter / Formatter”

On the next screens choose:

  • Sass / SCSS (with node-sass)
  • ESLint with error prevention only
  • Lint on save
  • In dedicated config files

You are of course free to make any other selections — it will not have any effect on how your App integrates with Electron later on.

Once the installer has finished you can run your App with the following commands:

cd my-app
npm run serve

Open your web browser and you will be greeted with Vue.js “Hello World” page:

Your Vue.js App was successfully installed

A note here: While the Browser developer tools usually work totally fine for debugging UI related issues, I strongly recommend you additionally install the “Vue Devtools” extension for your browser. You can find plugins / extensions for all common browsers here.

Adding Electron to your Vue.js App

There are multiple methods to add Electron to your App but we found that using the Vue CLI Plugin Electron Builder is by far the quickest and easiest method to get started.

Inside your project directory type:

vue add electron-builder

This will install Electron with all necessary dependencies and also configure the entire build process for your development and release packages. If you open the package.json file in your application folder, you will find that NPM scripts electron:serve and electron:build have been added. You can use serve for development and build for creating the executable packages for different operating systems.

Now go ahead and try running npm run electron:serve

Your first Vue.js / Electron App in action

If you see the above application opening — Congratulations! You have just successfully created your first Vue.js / Electron App. You can also try a production build with npm run electron:build and you should end up with an executable for your current platform inside the dist_electron folder which is ready for shipping.

You’re now basically all set and ready to start coding. Before you go ahead let’s have a more in-depth look into Electron and I will share some useful best practices with you.

Best practices for Electron Kiosk Apps

When you set up a fresh Electron App, your directory structure will look like this:

A fresh Electron App

As mentioned before the dist_electron directory is simply the location where your executables will be created when you build your App. The much more interesting file is background.js which we’re going to have a closer look at.

An important note here:
While it is tempting to use background.js for background tasks like Websocket servers or other long-running jobs, Do NOT do this! Keeping the background process busy will cause the UI of your App to become unresponsive. There are better methods for running background tasks in an Electron App which I will describe in another article.

The main application window

Open up background.js in your IDE and around line 17 you will find the function called createWindow which is responsible for opening the main window of your application. By default it is configured to create an 800x600px sized window and enable the NodeJS integration but there are (literally) a hundred additional options you can set. Here are some commonly used options for kiosk applications:

win = new BrowserWindow({
width: 800,
height: 600,
fullscreen: true,
frame: false,
autoHideMenuBar: true,
kiosk: true,
webPreferences: {
nodeIntegration: true
}
});

These settings will ensure your App runs in full screen mode without any window frame or menu bars. However just running your App in full screen mode is NOT enough and you should enable “kiosk” for some additional lockdown features such as:

  • Disable the F11 key to exit full screen
  • Disable keyboard shortcuts for navigating or creating new tabs / windows
  • Prevents other programs from popping up on your screen

Global application shortcuts

If you want to define your own key (or key combination) to exit the App, you can register a so-called “globalShortcut”. To enable global shortcuts, first import the function by adding it to the existing import like this:

import { app, protocol, globalShortcut, BrowserWindow } from 'electron'

Next find the line which registers the app.on('ready') event handler (around line 58) and insert the following code below createWindow():

globalShortcut.register('Escape', () => {
app.quit();
})

This will enable the ESC key to quit your App. You can of course also use different keys or key combinations.

Building and Packaging

You already learned that building and packaging your application is as easy as running npm run electron:build in your application directory. Still you might wonder how you can configure certain properties of your App package, such as the bundle name, the App icon or how to build for multiple platforms.

When you’re busy packaging stuff

Let’s start by setting our bundle name and icons. As we use Electron as a plugin for Vue.js, we need to add this configuration to a file called vue.config.js. If this file doesn’t exist yet you can create it as a new blank file in your application root directory.

The file itself should look like this:

module.exports = {
[... any other Vue.js configuration...]
pluginOptions: {
electronBuilder: {
builderOptions: {
productName: "My great App",
appId: "com.acme.mygreatapp"
mac: {
icon: 'src/assets/app.icns'
},
win: {
icon: 'src/assets/app.ico',
target: [
{
target: 'portable',
arch: ['x64']
}
]
}
}
}
}
}

The above file should be pretty self-explaining. You’re configuring the Electron Builder to use “My great App” as the application name and using “app.icns” and “app.ico” as icons for the macOS and Windows bundles. In addition the builder should create a portable 64bit executable for Windows.

Note that you CAN build Windows executables on macOS but you CAN NOT build macOS executables on Windows.

There are quite a lot of other options available if you need to build for different platforms or architectures. In my case I usually want to build a macOS executable to distribute to a group of testers and a portable (EXE file without installer) Windows 64 bit version for production. You can refer to the documentation here and here for additional configuration options.

What about Linux builds? Linux supports many different architectures (x86, arm, …) and does not have a single package format like DMG or EXE. Instead there are many options like AppImage, Snap, Deb etc, so you need to configure a build target that matches your requirements. For example if building for a Raspberry Pi 3 you will need to configure a linux build for “armv7l” architecture and use the “snap” target.

Going into lockdown

Electron Apps in kiosk mode already provide a decent amount of lockdown. If you want to further minimize the chance of the user closing the App and messing with the underlying operating system, here are some (Windows-only) measures we’ve used before:

Probably not the lockdown you had in mind

Do not launch the Windows desktop at all
Use these regedit modifications to directly load your App on boot instead of the Windows Desktop (explorer.exe). In case your App crashes or gets otherwise terminated there will just be a blank screen:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon]
"Shell"="D:\\path\\to\\your\\appFile.bat"

To revert:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon]
"Shell"="explorer.exe"

Prevent the Alt+F4 keyboard shortcut
Capture the “beforeunload” event on your main application window using the following code:

window.onbeforeunload = (e) => {
console.log('I do not want to be closed');
e.returnValue = false;
}

Conclusion

I hope this tutorial could help you understand what Electron is and how to use it in practice to build HTML5 based kiosk applications. There is of course still lots more to discover and I will share some more in-depth tutorials with you soon!

If you have any comments, questions or suggestions feel free to start a conversation in the comments.

--

--

Andreas Schallwig

A 20-year veteran in Asia's digital industry and an expert in creating immersive digital experiences using innovative technology.