The Startup
Published in

The Startup

Build a Growing Zone Finder With HTML, CSS, and JavaScript

Whether you are a gardening enthusiast or can’t keep a succulent alive (or don’t even know what a succulent is), this growing zone finder is an excellent project for beginning programmers looking to become more familiar with inputs, APIs, and JavaScript.

The completed project will look like this:

You can see a video of this zone tracker as part of a more extensive app here, and get the source code for this project on GitHub

Getting Started:

What is a Growing Zone?

A growing zone, or hardiness zone, is a national standard for knowing which plants will grow in which locations. The USDA divides North America into 11 growing (hardiness) zones; each zone is 10°F warmer — or colder — in an average winter than the adjacent zone. Knowing your growing zone is vital to successful gardening: it allows you to estimate the first and last frost dates of your location, plan when to start your seeds, and know which plants will thrive in your region.

Using an API, we can create an app that allows the user to enter their zip code and receive their corresponding zone, temperature range, and latitude and longitude.

What is an API?

API is an acronym for Application Programming Interface. APIs are software intermediaries that allow two applications to talk to each other and are essential in programming. Originally designed to connect code components running on the same machine, public APIs, like the one we will be using, are becoming more and more popular, allowing programmers to write code that interacts with other vendors’ and programmer’s code online.

When using a public API for programming, the company, or individual, will host information on their server and provide you with instructions regarding what you can do with their API, the information you will receive, and how to fetch and parse this information for use in your application.

Using the Phzmapi API

Like most public APIs, phzmapi allows users to request information from their server based on specified parameters. In this case, we need to pass through the user’s zip code as part of the URL used for the request.

The URL, with the five digit zip code injected, is:{zipcode}.json

This will return the following data in JSON format:

{"zone": "7a","temperature_range": "0 to 5","coordinates":{"lat": 38.89,"lon": -77.03}}

You can see a live example at

Building the Growing Zone Finder App:

I will be using Visual Studio Code, but you can use any text editor that you like. Start by creating a folder for the project and adding HTML, CSS, and JavaScript files. My file structure looks like this:

Challenge Yourself: If you are familiar with APIs, try creating the app without looking at the code based on the API information and video above.If this feels overwhelming, break the process down into small pieces. Start by creating the HTML page based on the video, then see if you can add the necessary JavaScript and styling.But, if you don’t feel comfortable trying this on your own yet, keep following along!

Step One: Build the Index.html Page

As you can see in the video above, the user interface that we are building needs to allow the user to:

  • Enter a zip code into a text box
  • Press a button to submit their zip code entry
  • See the results displayed on the screen

To create this, we will start by adding the basic HTML structure to the index.html page.

In the head section, let’s give our app a title and link it to our stylesheet.

<head><title>Growing Zone Finder</title><link rel=”stylesheet” href=”styles.css”></head>

Your file should look like this:

Then in the body, add:

A header (h1) to let the user know what the app is:

<h1>Growing Zone Finder</h1>

Two div sections:

One where the user can input and submit their zip code. Let’s give this div the class name ‘inputContainer.’

<div class=’inputContainer’></div>

The other to display the results. Let’s give this div the id ‘resultsContainer.’

<div id=’resultsContainer’> </div>

A link to the app.js files at the bottom of the body section

<script src=’app.js’> </script>

Your index.html file should look like this:

Now, let’s build out the input container div:

Start by providing brief instructions to let the user know to enter their zip code.

< label> Enter Your Zip Code to Find Your Growing Zone: </label>

Create a textbox for the zip code input, add a placeholder, and give this the id ‘zipCodeTB.’

<input type=’text’ placeholder=’Zip Code’ id=’zipCodeTB’ />

Add a button for the user to submit their entry. Give it the name ‘submit’ and id ‘submitButton.’

<button id=’submitButton’>Submit</button>

We will leave the results container empty and use the innerHTML property to input this information from the app.js page once the data is received.

Your index.html file should now look like this:

Step Two: Build the App.js Page

To build the JS required for this app, we need to:

  • Access the zip code text box, submit button, and results container from the index.html page.
  • Create a function that will fetch the data from the API based on the zip code entered
  • Create a function that will call the above fetch function when the user clicks the submit button and inserts the returned data into the results display on the index.html page

Access the HTML Elements:

To access the HTML elements, use the document method getElementByID, and the ids that we entered in step one to set these elements to variables on the JS page.

For the text box, we can do this by creating a variable zipCodeTB and setting it to the html element as follows:

let zipCodeTB = document.getElementById(‘zipCodeTB’)

Repeat this step with the appropriate variable name for the submit button and results container:

let submitButton = document.getElementById(‘submitButton’)let resultsContainer = document.getElementById(‘resultsContainer’)

Your app.js file should look this:

Fetch the Data From the API:

Next, let’s write the function that will make the API call.

One thing to keep in mind is that when we make a fetch request, there will be a slight delay between the time we send the request and when we receive the data. While this is typically just a millisecond, we need to ensure that the program has received this information before moving on to the next line dependent on this data, or else we will get an error.

The cleanest way to do this is to use an async function, which we can do by declaring the keyword “async” in front of the function and using one or more await expressions inside the function. An await expression will suspend the async function’s process until the awaited operation is either fulfilled or denied.

Let’s call the function “fetchZone” and pass in one parameter, the zip code.

async function fetchZone(zip) {}

Then make the fetch request, using the await expression to ensure the request fully processes before going to the next line. Insert the zip code into the URL using template literals, and set this to the variable “response.”

Remember to use backticks instead of a double or single quote when using template literals.

let response = await fetch(`${zip}.json`)

Once we have the response, we can extract the information in JSON format. Again we will want to use the await expression.

let zoneResults = await response.json()

And then return zoneResult.

At this point, your app.js file should look like this:

Add an Event Listener:

Now that we have our function to make the API call, we need a way to call it when the user submits their information via the submit button on the index.html page.

To do this, we will attach the event target method addEventListener to the submitButton variable. The addEventListener will listen for a specific event, in this case, the event type is a button ‘click,’ before calling the listener, the function that we want to initiate when the event occurs. The code will look like this:

submitButton.addEventListener(‘click’, async () => {  //code to call fetchZone and display results will go in here}

Note that we have used an arrow function as the listener and will place the code needed to call and receive data from the fetchZone function inside. Additionally, as this function will be relying on an asynchronous call, we want to make it an async function.

So far, your function should look like this:

We know that we want to call the fetchZone function inside our event listener, but to do so, we need to pass in the zip code that the user entered as a parameter.

We can do this by accessing the information entered into the zip code text box using the value property.

let zipCode = zipCodeTB.value

Then we can call our fetchZone function and pass in the zip code. We will also want to set the return of the function to a variable ‘result’ so we can return it to the user.

let result = await fetchZone(zipCode)

Your function should now look like this:

At this point, if you console log the result and run the program, you will see that:

  • The user can enter their zip code and click submit.
  • The submit click will trigger the event listener
  • The fetchZone function is called for the user-submitted zip code
  • The fetch request is made to the server, and the data returned
  • The returned data from the fetchZone function is set to the result variable in the event listener function in JSON format.

This means we now have access to the user requested data!

Display The Data:

The next step will be to display the data. While we have access to it at this stage, it is in JSON format and not yet presentable to the user. To show this in a more user-friendly manner, we will put it into a string and insert it into the results container on the index.html page.

In the event listener function, after we get the result, let’s create another variable set to the string that we are returning called “zone.”

Since this will be inserted into the inner html of the results container div, a clean way to do this is to create a div as the parent element of this string and inject the growing zone, temperature range, latitude, and longitude into the string using template literals, like so:

let zone = `<div class=”zoneDisplay”><h2> Your Growing Zone </h2><span>Zone: ${}</span><span>Temp Range: ${result.temperature_range}</span><span>Lat: ${}</span><span>Lon: ${result.coordinates.lon}</span></div>`

(Again, remember to use backticks instead of a double or single quote when using template literals.)

Then we will use the zone variable to update the inner HTML of the results container.

resultsContainer.innerHTML = zone

Now, when we get the result back, the information will be passed into a readable string and populated into the results container div on the index.html page.

One last thing to do is to clear out the user input in the text box in preparation for the next entry by setting the text box value to an empty string, as such:

zipCodeTB.value = ‘’

Your completed code should now look like this:

Step Three: Zip Code Validation

Now your app can take an input, make a fetch request, and display the returned data, but what happens if your user types an invalid zip code or leave the text box empty?

It crashes.

To keep this from happening, let’s add some code to validate the user input before calling the fetchZone function in the app.js file.

We can test the validity of a zip code by running a regular expression test. Inside the addEventListener function, we will set the constant for the zip code test so it knows what to look for, in this case, five digits.

const zipCodeRegex = /^\d{5}$/

To check the user’s zip code, we will use the test method, which you can do with the following code and passing in the zipCode variable from the existing function.


This test will return true or false, so we can use this to create an if/else statement letting the program know what to do if the zip code is valid (run the functions and return the display) or not (return a message letting the user know to enter a valid zip code).

//if the test returns true it will run the original functions
if (zipCodeRegex.test(zipCode)) {
//original fetch and display functions here//else if the test returns false it will populate a message into the results container for the user} else {
resultsContainer.innerHTML = ‘Please enter a valid zip code’
zipCodeTB.value = ‘’

Your listener should now look like this:

Step Four: Style Your App

Your stylesheet is already linked, so go ahead and design this app as you see fit.

If you are new to programming, use this as a chance to practice your CSS skills or familiarize yourself with some of the tools available, such as Bootstrap. You can even create and add graphics on free-to-use sites like Canva for some additional interest.

To style the app as seen in the video:

We already set the class name for the input container, make this a flexbox, set the flex-direction to “column”, and align the items in the center.

Add the class name “input” to the items in the input container on the HTML page, and add a 5px margin to these items in your CSS file.

<div class=’inputContainer’><label class=’input’> Enter Your Zip Code to Find Your Growing Zone: </label><input type=’text’ placeholder=’Zip Code’ id=’zipCodeTB’ class=’input’/><button id=’submitButton’ class=’input’>Submit</button></div>

Add the class name “displayZone” to the return display in the app.js file, make this a flexbox, set the flex-direction to column, and align the items in the center in your CSS file.

let zone = `<div class=”zoneDisplay”><h2> Your Growing Zone </h2><span>Zone: ${}</span><span>Temp Range: ${result.temperature_range}</span><span>Lat: ${}</span><span>Lon: ${result.coordinates.lon}</span></div>`

Your styles.css should look like this:

Step Five: Share What You Created!

Your app is complete! Commit your project to your GitHub account and share a screenshot or video of your app on social media.

Thank you for checking out this article and building along with me! I hope you had fun, and I would love to see what you created — drop a link to your GitHub repo in the comments below.



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Katy Donoghue

Katy Donoghue


Software Developer | Freelance Writer | Based in Savannah, GA