Building a Single Page App without frameworks 🔥 (2024)

Building a Single Page App without frameworks 🔥 (1)

Building a Single Page App without frameworks 🔥 (2)

Dom (dcode)

Posted on

Building a Single Page App without frameworks 🔥 (3) Building a Single Page App without frameworks 🔥 (4) Building a Single Page App without frameworks 🔥 (5) Building a Single Page App without frameworks 🔥 (6) Building a Single Page App without frameworks 🔥 (7)

In today's post we'll be building a Single Page Application using only vanilla JavaScript - this means we don't need to use any frameworks!

Frameworks are great, and in many cases you'd probably want to use one, but for those smaller projects, or if you'd just like more control, doing it yourself from scratch could be a viable option 👀

What are we going to be creating?

This will be a fairly simple Single Page Application which features a navigation bar and a "view" section on the right side that'll change as the navigation items are clicked on.

Building a Single Page App without frameworks 🔥 (8)

Video Tutorial

First up, as usual, if you'd prefer to see this tutorial in video form, feel free to check it out below.

Follow along with the source code

I recommend cloning the repository or simply viewing the source code while doing this tutorial.

Taken from my YouTube Tutorial:https://www.youtube.com/watch?v=6BozpmSjk-Y

A Quick Test-Drive

To give the completed code a quick test-drive:

  1. Install Node.js
  2. Navigate to the project folder and run the following from a terminal:
    • npm init -y (to create a Node.js project)
    • npm i express (to install Express)
    • node server.js (to run the server)
  3. Open localhost in a web browser, using the port specified in server.js e.g. http://localhost:3000/

Refer to the YouTube Tutorial for step-by-step instructions to create the code. Enjoy! :)




Creating the Web Server

We'll be using Express for our web server, so lets start by installing the dependencies and creating our directory structure.

npm init -ynpm i expressmkdir -p frontend/static

Next, we can create a server.js file and include the following.

const express = require("express");const path = require("path");const app = express();/* Ensure any requests prefixed with /static will serve our "frontend/static" directory */app.use("/static", express.static(path.resolve(__dirname, "frontend", "static")));/* Redirect all routes to our (soon to exist) "index.html" file */app.get("/*", (req, res) => { res.sendFile(path.resolve("frontend", "index.html"));});app.listen(process.env.PORT || 3000, () => console.log("Server running..."));

After this, create an index.html file within the frontend directory and start up your server:

node server.js

Navigating to http://localhost:3000 should now display your HTML file.

Writing the HTML

For the markup within index.html, we can include:

  • our soon-to-exist CSS stylesheet
  • our soon-to-exist JavaScript module
  • a navigation menu
  • an app container
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Single Page App (Vanilla JS)</title> <link rel="stylesheet" href="/static/css/index.css"></head><body> <nav class="nav"> <a href="/" class="nav__link" data-link>Dashboard</a> <a href="/posts" class="nav__link" data-link>Posts</a> <a href="/settings" class="nav__link" data-link>Settings</a> </nav> <div id="app"></div> <script type="module" src="/static/js/index.js"></script></body></html>

Note: the data-link attributes on our <a> tags - any links marked with this attribute will use the History API to enable changes to the view (#app) without a page refresh. We'll learn more about this shortly.

Also note: the #app div is used as the container for each view (Dashboard, Posts etc.) which we'll be learning more about a bit later on.

Adding the CSS

We may as well get the CSS over and done with so we have something pretty to look at - let's make a new file within frontend/static named main.css.

body { --nav-width: 200px; margin: 0 0 0 var(--nav-width); font-family: 'Quicksand', sans-serif; font-size: 18px;}/* Creates a full-height, left-mounted navigation menu */.nav { position: fixed; top: 0; left: 0; width: var(--nav-width); height: 100vh; background: #222222;}/* Making these look fantastic */.nav__link { display: block; padding: 12px 18px; text-decoration: none; color: #eeeeee; font-weight: 500;}.nav__link:hover { background: rgba(255, 255, 255, 0.05);}#app { margin: 2em; line-height: 1.5; font-weight: 500;}/* The 'dcode' green always needs to make an appearance */a { color: #009579;}

As the CSS isn't the main focus of this tutorial, I'm not going to go into detail on what those styles do - plus, most are quite self explanatory 😁

Moving onto the JavaScript

Let's create a new file within static/js named index.js. This will be the main entry point for the client-side JavaScript and will contain the code for the router.

Supporting client-side URL parameters

First things first, we need to write a function that will help with client-side URL parameters. For example, if I want to define a route for /posts/:id, I want to be able to access the Post ID within my code.

As we'll be matching with regular expressions, let's write a function that will convert our /posts/:id route into a regular expression pattern:

const pathToRegex = path => new RegExp("^" + path.replace(/\//g, "\\/").replace(/:\w+/g, "(.+)") + "$");

Now, calling pathToRegex("/posts/:id") will give us /^\/posts\/(.+)$/. We can now use the capture group to grab the Post ID value in the router.

Writing the router

Let's create another function called router - this one will be called on page load, when clicking on links and when navigation changes.

const router = async () => { const routes = [ { path: "/" }, { path: "/posts" }, { path: "/posts/:id" }, { path: "/settings" } ];}

Very shortly, we'll be including a reference to a "view", in the form of a JavaScript class, to each route.

For now though, let's write some code which will match a route with the current URL path.

const potentialMatches = routes.map(route => { return { route, result: location.pathname.match(pathToRegex(route.path)) };});

As you can see, we're simply providing a map function for each route, and returning an extra field called result - this will contain the regular expression result when matching location.pathname with our route.

Next, let's figure out which one of routes matched, and provide a default (not found) route if none of them matched.

let match = potentialMatches.find(potentialMatch => potentialMatch.result !== null);/* Route not found - return first route OR a specific "not-found" route */if (!match) { match = { route: routes[0], result: [location.pathname] };}

As you can see, we're simply finding the first route that had a regular expression result.

If none are found, we're just "mocking" the first route. Feel free to add your own "not-found" route here.

Lastly, we can log out the matched route. Shortly, we'll be adding some content within #app based on the matched route.

console.log(match);

Tying it all together

Before we continue creating the views and finishing up on our router, we should write some code which will tie all this together.

Let's start by defining a function that uses the History API to navigate to a given path.

const navigateTo = url => { history.pushState(null, null, url); router();};

Next, we can enable all links with the data-link attribute to make use of this function. Also, we can run the router on document load.

document.addEventListener("DOMContentLoaded", () => { document.body.addEventListener("click", e => { if (e.target.matches("[data-link]")) { e.preventDefault(); navigateTo(e.target.href); } }); /* Document has loaded - run the router! */ router();});

We'll also want to run the router when the user navigates with the back and forward buttons.

window.addEventListener("popstate", router);

With all this complete, you should now be able to hop inside the browser and try clicking on one of the navigation links.

Upon clicking on the links, notice how the URL changes based on each link without a page refresh. Also, check the console for your match - it should all be there 😁

Building a Single Page App without frameworks 🔥 (10)

Parsing the client-side URL parameters

Before moving onto writing the code for each of our views, we need a way to parse the client-side URL parameters. Let's define a function to do so.

const getParams = match => { const values = match.result.slice(1); const keys = Array.from(match.route.path.matchAll(/:(\w+)/g)).map(result => result[1]); return Object.fromEntries(keys.map((key, i) => { return [key, values[i]]; }));};

This function will take in a "match" - the same one we found via potentialMatches and the find method above.

Once it's got a match, it will take all of the capture group matches, from index 1 to the end. In the case of /posts/:id/:anotherParam and /posts/2/dcode, the value of values will be ["2", "dcode"].

In terms of keys, this will use a regular expression to grab each identifier prefixed with a : in our path. So, it will take /posts/:id/:anotherParam and give us ["id", "anotherParam"].

Lastly, we take the result of both values and keys, and stick them together with Object.entries which will give us a returned value of something like

{ "id": "2", "anotherParam": "dcode"}

We can now move onto writing the code for each view - after that though, we can make use of the getParams within the router.

Writing the views

Each "view" is going to be represented by a JavaScript class within frontend/static/js/views. We can first define an abstract class which each view will extend.

// frontend/static/js/views/AbstractView.jsexport default class { constructor(params) { this.params = params; } setTitle(title) { document.title = title; } async getHtml() { return ""; }}

This is quite straight forward - we're going to store the parameters for each view as an instance property, and provide a convenience method for setting the page title.

Most notably though, we have the async getHtml method - this one is going to be implemented by each view, and will return the HTML for them.

Let's write the code for the Dashboard view.

// frontend/static/js/views/Dashboard.jsimport AbstractView from "./AbstractView.js";export default class extends AbstractView { constructor(params) { super(params); this.setTitle("Dashboard"); } async getHtml() { return ` <h1>Welcome back, Dom</h1> <p>Hi there, this is your Dashboard.</p> <p> <a href="/posts" data-link>View recent posts</a>. </p> `; }}

As you can see, we're simply extended the AbstractView and calling a method to set the page title. You can also find the HTML for the Dashboard returned via getHtml.

Feel free to create as many views as you need.

Note: If your route had parameters, you can reference them within the views with this.params.your-param-here, for example, if you had a ViewPost view, get the Post ID by doing this.params.id.

Going back to the router

Now that we've got our views, let's make some slight adjustments to the index.js file.

Let's import our views.

import Dashboard from "./views/Dashboard.js";import Posts from "./views/Posts.js";import PostView from "./views/PostView.js";import Settings from "./views/Settings.js";

Now, we can reference them in the routes within the router function.

const routes = [ { path: "/", view: Dashboard }, { path: "/posts", view: Posts }, { path: "/posts/:id", view: PostView }, { path: "/settings", view: Settings }];

Lastly, we can make a new instance of the matched view and set the HTML of the #app container to be the HTML provided by the view.

const view = new match.route.view(getParams(match));document.querySelector("#app").innerHTML = await view.getHtml();

Note: We use a await here as the getHtml function may need to perform a request for data or HTML from the server-side.

And that's it! You should have a fully functional Single Page Application. Please provide any suggestions below 😁

Top comments (31)

Subscribe

Building a Single Page App without frameworks 🔥 (12)

fa*gner Brack

I believe ideas should be open and free (as in Freedom). This is a non-profit initiative to write about challenging stuff you won’t find anywhere else.

  • Email

    devto@fa*gnermartins.com

  • Location

    Sydney, Australia

  • Joined

• Edited on • Edited

Basically if you remove the javascript code and get the html fragment from the server using the "get html" function then everything still works.

Progressive enhancement at its best.

This is a proof that you don't need a front end framework to build an spa that can track states through the Url using the history API. No state on client side therefore no need for a "setState all the things".

Great post, rare to see such quality around the Web these days.

Building a Single Page App without frameworks 🔥 (14)

Comment deleted

Building a Single Page App without frameworks 🔥 (15)

fa*gner Brack

I believe ideas should be open and free (as in Freedom). This is a non-profit initiative to write about challenging stuff you won’t find anywhere else.

  • Email

    devto@fa*gnermartins.com

  • Location

    Sydney, Australia

  • Joined

• Edited on • Edited

[...] you want to write your front-end code all in a separate project and keep your back-end unaware of it

Why? They are still coupled but now with a weak layer between them with a home-made protocol to interpret the response body. Views should still be sent from the back-end systems unless your business logic is in your front-end code and back-end has no business logic. If that's the case you have a service that returns data, and that's called a database. If that's the case then well... use a database query language not HTTP.

HTTP is for hypertext/hypermedia state transfer, use the tools for what they're optimised for, don't try to repurpose them to something that makes absolutely no sense.

Building a Single Page App without frameworks 🔥 (17)

Cato

  • Joined

is that a node.js function? cant find any reference to it after a couple google hits

Building a Single Page App without frameworks 🔥 (19)

fa*gner Brack

I believe ideas should be open and free (as in Freedom). This is a non-profit initiative to write about challenging stuff you won’t find anywhere else.

  • Email

    devto@fa*gnermartins.com

  • Location

    Sydney, Australia

  • Joined

• Edited on • Edited

It's a reference to the code examples in the original post. There's a custom "getHtml()" function there.

Building a Single Page App without frameworks 🔥 (21)

Michael Currin

I'm a self-taught dev focused on websites and Python development.My friends call me the "Data Genie".When I get bored, I find tech to read about, write about and build things with.

  • Location

    Netherlands

  • Education

    Marketing honors + self-taught dev

  • Work

    Senior Software Engineer at ACT Commodities

  • Joined

• Edited on • Edited

Thanks for sharing!

I enjoyed going through the repo. I forked it and updated how the routes are handled so it works on GH Pages 🚀

github.com/MichaelCurrin/single-pa...

Also I added instructions for serving as a static site without Express.

Building a Single Page App without frameworks 🔥 (23)

Dear author, why you didn't use the hash part of the URL with the hashchange event to navigate around the app?
I've checked around 5 similar articles and all of them are recommending to use hash. It's much simpler and convenient.

Building a Single Page App without frameworks 🔥 (25)

aderchox

Web developer. Lover of Typescript. Also comfortable with a bunch of other shiny languages and "big-brain tech tools" to flex about at parties! ( ´・・)ノ(._.`)

  • Joined

It might be simpler, but it's a different thing. It depends on your preference based on your use case.

Building a Single Page App without frameworks 🔥 (27)

Michel Renaud

I’m not a cat. But cats rule.

  • Location

    Ottawa, Ontario, Canada

  • Education

    B.Sc. in Computer Science, Université de Sherbrooke, Canada

  • Work

    Programmer/analyst at Government of Canada

  • Joined

I'm interested in this. Do you have some links you can share?

Building a Single Page App without frameworks 🔥 (29)

James King

Web Developer / Gamer / Mountain Biker / Musician

  • Location

    Exeter, UK

  • Education

    Bsc Hons Computing & Game Development (First Class)

  • Work

    Software Engineer at Admiral Money

  • Joined

• Edited on • Edited

Just a side note: Express is itself, a framework.

I don't mean this as an inflammatory statement, just for those that may not know.

Building a Single Page App without frameworks 🔥 (31)

Michael Currin

I'm a self-taught dev focused on websites and Python development.My friends call me the "Data Genie".When I get bored, I find tech to read about, write about and build things with.

  • Location

    Netherlands

  • Education

    Marketing honors + self-taught dev

  • Work

    Senior Software Engineer at ACT Commodities

  • Joined

Express is more of a dev dependency here for local dev convenience and can be swapped out for other approaches, including VS Code Live Server or Python builtin HTTP server.

Or http-server for NPM which can be installed globally and run in the project root.

Building a Single Page App without frameworks 🔥 (33)

Michael Currin

I'm a self-taught dev focused on websites and Python development.My friends call me the "Data Genie".When I get bored, I find tech to read about, write about and build things with.

  • Location

    Netherlands

  • Education

    Marketing honors + self-taught dev

  • Work

    Senior Software Engineer at ACT Commodities

  • Joined

BTW In production you would use Nginx to serve your static assets (HTML and JS). Or upload them to GitHub Pages and let that serve it for you. No NPM server needed.

Using Express in production is suitable if you want to build an API or maybe do frontend templating (like Python Flask does). That you can make your content dynamic like with get data from a database. Instagram is a single application which does something like this.

Building a Single Page App without frameworks 🔥 (35)

Dom (dcode)

Web Developer from Australia that runs the YouTube Channel 'dcode' 😎

  • Location

    Australia

  • Work

    Web Developer

  • Joined

True - more accurately I probably should have mentioned "front-end" framework

Building a Single Page App without frameworks 🔥 (37)

Hi I am new with the javascript node etc. and I have a big problem :( How can I add script event to following HTML page
async getHtml() {
return
<h1>Welcome back, Dom</h1>
<p>Hi there, this is your Dashboard.</p>
<p>
<a href="/posts" data-link>View recent posts</a>.
</p>
;
}

I am trying to create forms in each page and I have to add script events in order to collect data and display current time on some forms etc. Thanks :)

Building a Single Page App without frameworks 🔥 (39)

Did you ever have any luck adding handles for the html in the views? Im trying to add event listeners to some input box I have in the html but have had no luck retrieving user input

Building a Single Page App without frameworks 🔥 (41)

Dear dom,

Thank you for your great article. I'm looking for a proper way to get totally ride of any server side framework. Imagine a project you cannot install anything in server. There is only an API to provide content.
Is there a way, to simply route to html pages and call some js to fill them ( statics, content .. ) ? What will be "bad" to do like this ?

Best regards, Wil

Building a Single Page App without frameworks 🔥 (43)

Adam Crockett 🌀

How’s it going, I'm a Adam, a Full-Stack Engineer, actively searching for work. I'm all about JavaScript. And Frontend but don't let that fool you - I've also got some serious Backend skills.

  • Location

    City of Bath, UK 🇬🇧

  • Education

    10 plus years* active enterprise development experience and a Fine art degree 🎨

  • Work

    Web Development Consultant at ForgeRock

  • Joined

Sombody might find this useful for a frame-workless SPA. Please note I wrote it.

Building a Single Page App without frameworks 🔥 (45) adam-cyclones / reactive-css-properties

Set css custom properties and react to changes in realtime from JavaScript

Building a Single Page App without frameworks 🔥 (46)

A tiny library to supercharge your styling workflow. With Reactive CSS Properties (re.css) you can set css custom properties and react to changes in realtime from JavaScript

Website-Report a bug-Supported frameworks

Table of contents

The case for re.css

You can think of modern JavaScript having two main responsibilities, updating business logic and updating styling, The trouble with the latter is that this adds extra overhead and new problems to overcome, re.css sets out that it is css's responsibility to update styling and JavaScript should…




Building a Single Page App without frameworks 🔥 (47)

Single Page App without frameworks, but you're using React which is a framework. I also wouldn't call it vanilaa javascript either, but that's just me

Building a Single Page App without frameworks 🔥 (49)

Daniele Carta

I'm live in Milano, I'm a Team Leader and Frontend Developer 💻 with +5 years of experience.

  • Email

    crtdaniele@gmail.com

  • Location

    Milano

  • Work

    Team Leader Frontend at Illimity Bank

  • Joined

React is not a framework, but it is a library.
In this article, I don't see React.

Building a Single Page App without frameworks 🔥 (51)

Ali Nazari

I currently spend my time on my blog https://ditty.ir. I write, I code. I learn, I love this :)

  • Location

    Iran

  • Work

    Web Developer

  • Joined

I hate people saying "React is not a framework. It's a library".
Yes, officially it's true. But what do other frameworks offer that React doesn't?

Building a Single Page App without frameworks 🔥 (53)

Hello Drew,

Can you point me where you see React stuff in it ?

Building a Single Page App without frameworks 🔥 (55)

I had a problem using this pattern, which I still don't know how to solve.
While a page is loading and a user clicks on some link to go to another page, the next page starts to be assembled with the requests that were still happening on the previous page and creates a page with the mixed content.

Building a Single Page App without frameworks 🔥 (57)

How to do simple state management with this approach?

Building a Single Page App without frameworks 🔥 (59)

Allen Jones

I love computer programming

  • Email

    aljay3334@gmail.com

  • Joined

Thanks for sharing.
How do I deploy the static website together with the node on firebase or github pages?

Building a Single Page App without frameworks 🔥 (61)

Ravgeet Dhillon

Full Stack Developer / Technical Content Writer

  • Email

    ravgeetdhillon@gmail.com

  • Location

    India

  • Education

    M. Tech in Computer Science and Engineering

  • Work

    Software Engineer at CloudAnswers

  • Joined

How do I write JS for each route and then inject it to the app when the route is loaded?

Building a Single Page App without frameworks 🔥 (63)

If I click on Posts, then I want to load a JS script file (click Handler). How I make it?

Building a Single Page App without frameworks 🔥 (65)

github.com/Graidenix/vanilla-router is a simple router for self-made SPA

Building a Single Page App without frameworks 🔥 (67)

how to create separate html files to run javascript return code

For further actions, you may consider blocking this person and/or reporting abuse

Building a Single Page App without frameworks 🔥 (2024)

FAQs

Can you build an app without a framework? ›

Building web applications without frameworks can be like crafting a piece of art using only basic tools and your creativity. While frameworks provide structure and efficiency, going without one allows for a more hands-on, personalized experience.

How do I make a single page app? ›

To produce a single-page application, you are going to need JavaScript. Your development team can either use pure JavaScript or try JavaScript frameworks like Vue, Angular, and React. Every single-page application framework has its own pros and cons, and we've discussed them deeply in a previous article.

How do I create a single-page application without React? ›

The most popular way to build a SPA with vanilla JavaScript is with Ajax, which can be found in frameworks like jQuery. However, with Ajax I would have to manually determine what content I want to refresh on the page and how to replace it as well as setup the event handling to actually trigger these page changes.

Do you really need a framework? ›

No framework is going to do everything for you. At most, the framework acts as a tool you need to know how to use. Nothing will replace fundamental programming skills and problem-solving abilities. Frameworks come and go—falling in and out of popular use—but good programming skills can last forever.

Do you have to use frameworks? ›

The answer to this question is almost always yes. Frameworks tend to be built to solve specific problems, and solve them very well. For instance, frameworks such as EntityFramework can save you entirely from writing SQL-code. Which can be fantastic if your programming team is not fluent in SQL.

Are single page applications worth it? ›

The most important benefits of single-page applications include the following: Improved speed and responsiveness. Faster loading times are the result of the SPA only needing to load the information necessary based on the user's action rather than loading an entire page from scratch. Greater stability.

What is a single-page application called? ›

An SPA (Single-page application) is a web app implementation that loads only a single web document, and then updates the body content of that single document via JavaScript APIs such as Fetch when different content is to be shown.

How much does a single page app cost? ›

$90-$400 is the estimated cost for a single-page app with no external scripts and inline CSS. This will take 3-4 hours. Complex apps can take 50 to 100 hours to develop. The estimated cost of development will be 1500-$10000.

Can you build a react app without a backend? ›

Create React App doesn't handle backend logic or databases; it just creates a frontend build pipeline, so you can use it with any backend you want. Under the hood, it uses Babel and webpack, but you don't need to know anything about them.

Is React good for single page? ›

React. js has proven to be a versatile and powerful library for building both Single Page Applications (SPAs) and Multi-Page Applications (MPAs).

Is React only for single page apps? ›

Commonly used for single-page applications (SPAs) and multi-page applications, with Server-Side Rendering available as well through libraries like Next. js or Remix.

Is it possible to implement a web project without JavaScript? ›

it's possible to create a website without JavaScript. But if you want make it more stronger, more function and to do awesome thing you must have to use JavaScript. You could find other alternatives, but with many drawbacks.

Can you code without a framework? ›

Coding from scratch means developing a web application without using any web framework or third-party library. You have to write all the code yourself, from the front-end to the back-end, using only the core features of the language or technology you choose.

Can you do automation without a framework? ›

The answer is YES! Of course, you can automate a test without these guidelines. Even though these guidelines are optional and testers can still script or record tests without adhering to them, employing a structured framework frequently provides testers with additional benefits that they would otherwise lose.

Are frameworks necessary for web development? ›

They're often essential to modern web development as they can increase developer efficiency and make it easier to scale. Here's what you need to know to pick the right framework for your company.

Top Articles
Latest Posts
Article information

Author: Duncan Muller

Last Updated:

Views: 5457

Rating: 4.9 / 5 (59 voted)

Reviews: 90% of readers found this page helpful

Author information

Name: Duncan Muller

Birthday: 1997-01-13

Address: Apt. 505 914 Phillip Crossroad, O'Konborough, NV 62411

Phone: +8555305800947

Job: Construction Agent

Hobby: Shopping, Table tennis, Snowboarding, Rafting, Motor sports, Homebrewing, Taxidermy

Introduction: My name is Duncan Muller, I am a enchanting, good, gentle, modern, tasty, nice, elegant person who loves writing and wants to share my knowledge and understanding with you.