Create your own iOS widget with JavaScript
Tags: javascript, showdev, ios
Published: 2021-01-26 15:58:28

---
title: Create your own iOS widget with JavaScript
published: true
description: How to create your own iOS home screen widget with pure JavaScript
tags: javascript, showdev, ios
//cover_image: https://direct_url_to_image.jpg
---
# What we will build
We will create our own iOS widget with pure JavaScript. To achieve this, we will use a great app called Scriptable. With Scriptable, you can create JavaScript scripts and run them on your iOS device. You can use these scripts to automate different things on your device and also display the script in an iOS home screen widget.
The main goal of this tutorial is to provide a starting guide for creating Scriptable widgets. Therefore we will build a simple widget to learn the basics and some useful tricks for building Scriptable widgets. The created widget will display the next scheduled launch date of SpaceX, as shown in the image below.
![iOS home screen with widget](https://dev-to-uploads.s3.amazonaws.com/i/6wclinxt7echdgg93fp3.jpeg)

# Prerequisites
Some basic knowledge of JavaScript will be helpful but is not necessary. As previously mentioned, we use the [Scriptable](https://scriptable.app) app for creating our widget, so you have to install it on your device.
For easier development and testing on macOS, I recommend the [Scriptable desktop app](https://scriptable.app/mac-beta/) (beta).
An alternative is syncing your scripts using iCloud and edit the Scripts inside the iCloud folder on your desktop, which should also work on other operating systems. This allows you to edit the script in your favorite text editor and test it on your iOS device. 

# Creating the widget
Now we are all set up to start creating our widget.
First of all, create a new empty script and add the following snippet.

```javascript 
async function createWidget() {
  // Create new empty ListWidget instance
  let listwidget = new ListWidget();

  // Return the created widget
  return listwidget;
}

let widget = await createWidget();

// Check where the script is running
if (config.runsInWidget) {
  // Runs inside a widget so add it to the homescreen widget
  Script.setWidget(widget);
} else {
  // Show the medium widget inside the app
  widget.presentMedium();
}
Script.complete();
```

This snippet adds a new function for creating and returning a new widget instance. In the next step, the widget will be created and set if the script is executed inside a home screen widget. If the script runs inside the Scriptable app, it will display a preview of the widget.
The preview is handy because the widgets don't refresh immediately. In contrast, the preview is always up to date when you run the script.
If you run the script inside the app, you should now see an empty white square. 🎉🎉

# Adding Content
Now that we can run a basic widget, let's add some content. The widget layout is based on stacks that hold the different displayed elements. The stacks can be nested into each other. By default, a ListWidget stacks its content vertically, which can be changed if you want it. 

> **Tip #1**
> When you want to debug more complex layouts, add a colored border to your elements so you can easily detect its size and position. 

First we will set the background color and after that we add some heading to our widget and give it some styling. Therefore paste the following snippet inside the `createWidget()` method after the `new ListWidget();`.
```javascript
  // Set new background color
  listwidget.backgroundColor = new Color("#000000");
  
  // Add widget heading
  let heading = listwidget.addText("🚀Next🚀");
  heading.centerAlignText();
  heading.font = Font.lightSystemFont(25);
  heading.textColor = new Color("#ffffff");
  
  // Spacer between heading and launch date
  listwidget.addSpacer(15);
```

To set the background color, we set the `backgroundColor` property of the created list widget instance. We assign a new color with the hex value `#000000`, which will give us a black background.
After that, we add a new text to our widget and save it in the heading variable. Using the variable, we can now access the added text and give it some styling. In our case, we will align the text center, change the default font and give it a white text color. If you are interested in the different options for the text and the other supported fonts, please visit the [WidgetText](https://docs.scriptable.app/widgettext/) and the [Font](https://docs.scriptable.app/font/) documentation of scriptable. 
Lastly, we add some spacing between our created heading and the next element, which will be our launch date. 

# Getting the data
To display the next scheduled launch date, we have to fetch our data from the API. Therefore we will use the following API [Documentation spacexdata.com API](https://github.com/r-spacex/SpaceX-API/blob/master/docs/v4/README.md).
> ⚠️ **Sidenote** ⚠️
> If you use an API that requires an API key or secret, never share your script with the key inside.  Every other person could use the API with your access if the key gets public, e.g. on GitHub. Always store the key in a variable at the beginning of your script to easily find and remove it before sharing. Even better, don't hard code the key and instead pass it as an [argument](https://docs.scriptable.app/args/) to your script.

To fetch the data from the api we will add the following two new functions to our script. 
```javascript 
async function getNextLaunch() {
  // Query url
  const url = "https://api.spacexdata.com/v4/launches/next";

  // Initialize new request
  const request = new Request(url);

  // Execute the request and parse the response as json
  const response = await request.loadJSON();

  // Return the returned launch data
  return response;
}

function getLaunchDateTime(launchData) {
  // Parse launch date to new date object
  const launchDateTime = new Date(launchData.date_utc);
  return launchDateTime;
}
```
The first function sends a request to the specified URL and parses the response as JSON, which will then be returned. The second function is just a little helper that will extract the date string from the provided dataset and return it as a date object.
Now we can call the previously defined functions inside `createWidtet()` to fetch the data from the api and get the launch date. Therefore simply add the following lines inside the `createWidtet()` function after the `listwidget.addSpacer()`
```javascript
  // Fetch next launch date
  let launch = await getNextLaunch();
  let launchDateTime = getLaunchDateTime(launch);
```

# Displaying the fetched data
Now that we have fetched our API data, we need to display it inside our widget. To achieve this, we create two new functions that will add our text to the widget and apply some basic formatting to it. 

```javascript 
function addDateText(stack, text) {
  let dateText = stack.addText(text);
  dateText.centerAlignText();
  dateText.font = Font.semiboldSystemFont(20);
  dateText.textColor = new Color("#ffffff");
}

function displayLaunchDateTime(stack, launchDateTime, precision) {
  // Check if next launch date is precise enough and display different details based on the precision
  if (precision == "hour") {

    // Add launch date
    const dateOptions = { year: "numeric", month: "2-digit", day: "2-digit" };
    let datestring = launchDateTime.toLocaleDateString(undefined, dateOptions);
    addDateText(stack, datestring);

    // Add launch time
    const timeOptions = { hour: "numeric", minute: "numeric" };
    let timestring = launchDateTime.toLocaleTimeString(undefined, timeOptions);
    addDateText(stack, timestring);
  } else if (precision == "day") {

    // Add launch date
    const dateOptions = { year: "numeric", month: "2-digit", day: "2-digit" };
    let datestring = launchDateTime.toLocaleDateString(undefined, dateOptions);
    addDateText(stack, datestring);
  } else {
    addDateText(stack, "No day for next launch given");
  }
}
```
The `addDateText()` function gets an instance to which the function should add the text and a string that holds the text which should be displayed. After that, the function adds the given text to the given stack and applies some styling to the element.

> **Tip #2**
> If you want to display some text with a variable length, you can add a `minimumScaleFactor()` between 0 and 1 to the text. This specifies the amount the text will scale down to fit inside the widget.

The `displayLaunchDateTime()` function is a bit more complex. It gets the instance to which the text should be added, the DateTime instance which should be displayed, and a precision parameter. The precision is sent with the API response of the next launch. It determines how precisely the launch time is known, which we will use to decide if we only display the day or also the time of the launch.
Inside the `displayLaunchTime()` function, we check the given precision. Based on that, we apply the correct format to our Date instance and add it to the stack by calling `addDateText()`. If the next launch date is not known precisely enough, we display a message that the next launch day isn't known yet. 

Now inside our `createWidget()` function we can call the `displayLaunchDateTime()` function and pass our listwidget instance, the created date and the precision from the API response to display the data. The final `createWidget` function is shown below.
```javascript 
async function createWidget() {
  // Create new empty ListWidget instance
  let listwidget = new ListWidget();

  // Set new background color
  listwidget.backgroundColor = new Color("#000000");

  // Add widget heading
  let heading = listwidget.addText("🚀Next🚀");
  heading.centerAlignText();
  heading.font = Font.lightSystemFont(25);
  heading.textColor = new Color("#ffffff");
  
  // Spacer between heading and launch date
  listwidget.addSpacer(15);
  
  // Fetch next launch date
  let launch = await getNextLaunch();
  let launchDateTime = getLaunchDateTime(launch);

  // Add the launch time to the widget
  displayLaunchDateTime(listwidget, launchDateTime, launch.date_precision);

  // Return the created widget
  return listwidget;
}
```

# Add it to your home screen
To display the widget on your home screen, you need to create the script inside the Scriptable app (you can find the final script in the Gist below). After that, add a new small Scriptable widget to your home screen, which should give you an empty widget. Now you can long-press the widget, edit the widget and select your created script in the widget configuration. 
That's it you should now see your created widget on your screen. 🚀🚀

I hope you enjoyed this little tutorial. Feel free to write to me if you encounter any issues or want to suggest some additional topics about which I should make a tutorial.

Happy coding 👨🏼‍💻 

{% gist https://gist.github.com/matthri/9602852b5bbfba3445c4e13f167d0666 %}