Create your account

Already have an account? Login here

Note: By joining, you will receive periodic emails from Coursetro. You can unsubscribe from these emails.

Create account

Creating and Using Windows in Electron

By Gary simon - Nov 29, 2017

This tutorial is based on our 100% free course: Creating Desktop Apps with Electron Tutorial

In the previous lesson, we focused on learning about Menus in Electron. In this lesson, we will begin to develop our app's UI (User Interface) for our bitcoin price alert app.

Let's get started!

If you prefer watching a video..

Be sure to Subscribe to the Official Coursetro Youtube Channel for more videos.

..video coming soon..

First Things First

To this point, we haven't organized our project very much in terms of folder structure because we haven't had to. Now that we will have some new files for another app window, it's worth establishing some organization.

This is what the current file and folder structure looks like:

/node_modules
index.html
main.js
package-lock.json
package.json

Create a new folder called /src and move the index.html inside of it:

  /node_modules
  /src
    index.html
main.js
package-lock.json
package.json

For each window, we're also going to create an associated JavaScript file with the same name. This means we will create a new file inside of /src/ called index.js and because we want another window, the second will be called add.html and add.js:

  /node_modules
  /src
    add.html
    add.js
    index.html
    index.js
main.js
package-lock.json
package.json

The contents of the 3 new files can remain empty for now.

Because we changed the location of the index.html to /src/index.html, we have to update the new location in our /main.js file:

// FROM
pathname: path.join(__dirname, 'index.html'),

// TO
pathname: path.join(__dirname, 'src/index.html'),

We have also had to keep reloading our project every time we make a change, but there's a handle package called electron-reload that would be worth installing, which refreshes the app automatically upon certain file changes.

Visit your console and type:

$ npm install electron-reload --save-dev

And add the following line to the top of the /main.js file:

require('electron-reload')(__dirname)

Great!

Working with the Templates

Open up /src/index.html and add a reference to a CSS file between the <head> tags:

<link rel="stylesheet" href="../assets/css/main.css">

Our assets folder doesn't yet exist, so create both /assets/ and /css inside of assets, and a blank css file named both main.css and add.css:

  /assets
    /css
      add.css
      main.css
  /node_modules
  /src
    add.html
    add.js
    index.html
    index.js
main.js
package-lock.json
package.json

Then, back in /src/index.html replace the HTML content within the <body> tags with:

    <div class="row">
        <div id="price-container">
            <p class="subtext">Current BTC USD</p>
            <h1 id="price">$9,503.21</h1>
        </div>
        <div id="goal-container">
            <p><img src="../assets/images/up.svg"><span id="targetPrice">Choose a Target Price</span></p>
        </div>
        <div id="right-container">
            <button id="notifyBtn">Notify me when..</button>
        </div>
    </div>

    <script src="index.js"></script>

We will not be using any type of CSS framework because the markup is rather minimal. But the <button id="notifyBtn"> is what will launch our secondary window.

Before we get to that however, let's also specify the HTML for our add.html template. In the <head> tags:

    <link rel="stylesheet" href="../assets/css/main.css">
    <link rel="stylesheet" href="../assets/css/add.css">

And in the <body> tags:

    <p class="notify">Notify me when BTC reaches..</p>

    <div class="row2">
        <div>
            <input id="notifyVal" placeholder="USD">
        </div>
        <button id="updateBtn">Update</button>
    </div>

        <a id="closeBtn">Close Window</a><br>

    </div>
    <script src="add.js"></script>

This will present the user with a form that has an input area from which they can specify a US Dollar amount to be notified when the actual price of Bitcoin exceeds said amount.

We will also need to create an images folder inside of assets and place the following file inside of it (right click and save file as).

Styling the Templates

I know, I know.. I haven't talked about launching actual windows yet, but don't worry, we're getting there. This is all important stuff because this course is based on an actual project.

Visit /assets/css/main.css and paste the following CSS rulesets:

@import url('https://fonts.googleapis.com/css?family=Montserrat:300,600');

body {
    background: #262626;
    color:#fff;
    font-family: 'Montserrat';
    margin:0;
}

.row {
    width:100%;
    margin-top:50px;
    background:#1A1A1A;
    border-bottom: 3px solid #FF0057;
    display: grid;
    grid-template-columns: 35% auto 35%;
    align-items: center;
}

#price-container {
    margin-left: 20%;
    background:#353535;
    padding: 0 10px;
    text-align:center;
}
#goal-container {
    padding:20px;
}
.subtext {
    font-size:.8em;
    text-transform:uppercase;
    margin-bottom: 10px;
}
img {
    width: 20px;
}

h1 {
    margin: 0 0 10px 0;
}

button {
    float:right;
    background:#FF0057;
    border:none;
    color:#fff;
    text-transform:uppercase;
    padding:10px;
    margin-right: 30px;
    cursor:pointer;
}

I won't describe what's happening here, but nothing too fancy. We are using the new CSS Grid, though!

In /assets/css/add.css paste the following:

body {
    background:#DFDFDF;
    color:#000;
    overflow:hidden;
}

p.notify {
    background:#C3C3C3;
    margin:0;
    padding: 20px;
    text-transform:uppercase;
    -webkit-app-region: drag;
}

.row2 {
    width:100%;
    display: grid;
    grid-template-columns: auto auto;
    padding:20px;
}

input {
    padding:12px;
}

#closeBtn {
    cursor:pointer;
    padding:20px;
    text-decoration:underline;
}

If you save this and launch the app with npm start in the console, this is what your app should now look like:

Great! If you click on the button NOTIFY ME WHEN.. nothing happens, so let's make it create the actual window. Whew, that was a lot of work, finally!

Launching a New Window in Electron

The first thing we need to concern ourselves is defining the necessary variables at the top of our blank /src/index.js file:

const electron = require('electron')
const path = require('path')
const BrowserWindow = electron.remote.BrowserWindow

BrowserWindow will allow us to launch a new window in our Electron app.

Next, we need to create a variable that will allow us to listen for click events on the notify button itself:

const electron = require('electron')
const path = require('path')
const BrowserWindow = electron.remote.BrowserWindow

const notifyBtn = document.getElementById('notifyBtn')

notifyBtn.addEventListener('click', function (event) {
  // Stuff here soon
})

This is straight-up JavaScript (sometimes referred to as Vanilla Javascript). It's a lot more work than using something like jQuery, Angular, Vue, etc., but I wanted to keep this JS-agnostic.

When the button is clicked, we want to launch that new window which will show our add.html template. To do so:

notifyBtn.addEventListener('click', function (event) {
  const modalPath = path.join('file://', __dirname, 'add.html')
  let win = new BrowserWindow({ width: 400, height: 200 })
  win.on('close', function () { win = null })
  win.loadURL(modalPath)
  win.show()
})

First, we're defining the file location of add.html.

Next, we create a new instance of BrowserWindow win, and defining the width and height.

From there, we do some cleanup if it's closed, we load the path of add.html and then .show() it.

Give it a shot by running npm start!

Okay, this looks good and all, but do we really need the frame with the title and the menu?  No!

Creating a Frameless Window in Electron

Going back to our /src/index.js file, modify our let win line to:

  let win = new BrowserWindow({ frame: false, width: 400, height: 200 })

There. All it takes is setting the frame property to false. Reload, and it should now look like this:

Ah, great!

Making a Window Transparent

If you're ever going to make a window transparent, make sure you do it correctly. You can very quickly make your app difficult to use if you're making it transparent!

None the less, let's give our window a slight bit of transparency. 

Open up /src/index.js and modify our let win line:

  let win = new BrowserWindow({ frame: false, transparent: true, width: 400, height: 200 })

Next, we define the amount of transparency in the CSS. 

Open up assets/css/add.css and add the following ruleset:

html, body {
    background: rgba(226, 226, 226, 0.5);
    height:100%;
}

Here, we're giving the background color a very light color (nearly white) and setting the opacity to 50%.

Reload the project and move the Add window around and you will see the slight bit of transparency:

Great! One thing that's slightly annoying, is that if you select the main window, our notify window becomes hidden behind it. Let's make it stick.

Making a Sticky Window in Electron

Once again, we only have to modify our let win line in /src/index.js by adding another property and value:

    let win = new BrowserWindow({ 
        frame: false, 
        transparent: true, 
        alwaysOnTop: true,    // Add this line
        width: 400, 
        height: 200
    })

I decided to organize the code better, now that we have several properties.

Reload the project, and our Add Window will always remain in view on the screen! This is really awesome stuff, isn't it?

Closing Windows in Electron

Now that our Add Window is stuck on the screen, let's make that Close Window button actually work.

The JavaScript to achieve this is very similar to our current /src/main.js file. In the /src/add.js file, add:

const electron = require('electron')
const path = require('path')
const remote = electron.remote
const closeBtn = document.getElementById('closeBtn')

closeBtn.addEventListener('click', function (event) {
    var window = remote.getCurrentWindow();
    window.close();
})

The magic happens when we use remote with the .getCurrentWindow() method. Once we have access to the current window, we can use .close() to close it!

Run npm start and you will now be able to close the window.

Going Forward

Our templating is finished, we can create menus and launch windows. But our actual doesn't actually function.

In the next lesson, we're going to integrate an HTTP library to make a call to a cryptocurrency service and retrieve the current value of Bitcoin, and display it in our UI.

This tutorial is based on our 100% free course: Creating Desktop Apps with Electron Tutorial

 


Share this post




Say something about this awesome post!