Latest Posts

How to design a website template on weight loss?

Loading

Chapter 7 — Add Interactivity With JavaScript

Introduction

A website can look beautiful without JavaScript, but modern templates often need interaction.

When a visitor opens a mobile menu, expands an FAQ, clicks a tab, submits a form, closes a notification or interacts with a small calculator, something needs to respond to that action.

That is where JavaScript becomes useful.

In the previous chapters, HTML provided the structure and CSS created the visual appearance. Now JavaScript will provide behavior.

The basic relationship is:

HTML → What the element is

CSS → How the element looks

JavaScript → What the element does

For a commercial weight-loss website template, JavaScript should be used carefully. The goal is not to add dozens of flashy effects. The goal is to improve usability and create useful interactions.

A good template feels responsive without feeling complicated.

7.1 Create the JavaScript File

Inside your project folder, create:

js/
└── script.js

Then connect it to your HTML:

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

The defer attribute allows the browser to load the script without unnecessarily blocking the HTML parser.

This is a simple but useful performance practice.

7.2 Start With Strict JavaScript

At the beginning of your JavaScript file, you can use:

'use strict';

This helps catch certain programming mistakes.

Then write your code in small sections.

For example:

'use strict';

document.addEventListener('DOMContentLoaded', () => {
    // Website functionality goes here
});

This ensures your code executes after the document has been parsed.

7.3 Build the Mobile Navigation

One of the most important interactions is the mobile menu.

Your HTML might contain:

<button
    class="menu-toggle"
    type="button"
    aria-label="Open navigation menu"
    aria-expanded="false">
    <span></span>
    <span></span>
    <span></span>
</button>

Your navigation might have:

<nav class="main-navigation" id="site-navigation">

Connect the two:

const menuButton = document.querySelector('.menu-toggle');
const navigation = document.querySelector('.main-navigation');

if (menuButton && navigation) {

    menuButton.addEventListener('click', () => {

        const isOpen = navigation.classList.toggle('active');

        menuButton.setAttribute(
            'aria-expanded',
            String(isOpen)
        );

    });

}

Now clicking the button adds or removes the active class.

CSS controls what the active menu looks like.

JavaScript controls when that state changes.

7.4 Improve the Mobile Menu Label

The button should communicate its current state.

menuButton.addEventListener('click', () => {

    const isOpen = navigation.classList.toggle('active');

    menuButton.setAttribute(
        'aria-expanded',
        String(isOpen)
    );

    menuButton.setAttribute(
        'aria-label',
        isOpen ? 'Close navigation menu' : 'Open navigation menu'
    );

});

This is a small improvement that makes the component clearer.

7.5 Close the Menu When a Link Is Selected

On mobile, visitors usually expect the menu to disappear after selecting a page.

const navLinks = navigation.querySelectorAll('a');

navLinks.forEach(link => {

    link.addEventListener('click', () => {

        navigation.classList.remove('active');

        menuButton.setAttribute(
            'aria-expanded',
            'false'
        );

        menuButton.setAttribute(
            'aria-label',
            'Open navigation menu'
        );

    });

});

This creates a smoother navigation experience.

7.6 Close the Menu With Escape

Keyboard interaction is important.

document.addEventListener('keydown', (event) => {

    if (event.key === 'Escape') {

        navigation.classList.remove('active');

        menuButton.setAttribute(
            'aria-expanded',
            'false'
        );

        menuButton.setAttribute(
            'aria-label',
            'Open navigation menu'
        );

    }

});

Now the visitor can press Escape to close the menu.

7.7 Build an FAQ Accordion

In Chapter 6, we used the native HTML <details> element.

That means you do not actually need JavaScript to make the FAQ work.

This is an important lesson:

Do not use JavaScript when HTML already provides the functionality you need.

However, if you want a custom accordion where only one question can remain open at a time, JavaScript can help.

Example:

const faqItems = document.querySelectorAll('.faq-item');

faqItems.forEach(item => {

    item.addEventListener('toggle', () => {

        if (item.open) {

            faqItems.forEach(otherItem => {

                if (otherItem !== item) {
                    otherItem.open = false;
                }

            });

        }

    });

});

This creates a one-open-at-a-time FAQ.

7.8 Create a Back-to-Top Button

Long pages can benefit from a back-to-top button.

HTML:

<button
    class="back-to-top"
    type="button"
    aria-label="Back to top">
    ↑
</button>

JavaScript:

const backToTop = document.querySelector('.back-to-top');

if (backToTop) {

    window.addEventListener('scroll', () => {

        if (window.scrollY > 500) {
            backToTop.classList.add('visible');
        } else {
            backToTop.classList.remove('visible');
        }

    });

    backToTop.addEventListener('click', () => {

        window.scrollTo({
            top: 0,
            behavior: 'smooth'
        });

    });

}

CSS can control the visibility.

.back-to-top {
    opacity: 0;
    pointer-events: none;
}

.back-to-top.visible {
    opacity: 1;
    pointer-events: auto;
}

Keep such controls subtle.

They should help visitors, not dominate the page.

7.9 Add a Sticky Header

A sticky header can improve navigation on long pages.

CSS can often handle this without JavaScript:

.site-header {
    position: sticky;
    top: 0;
}

This is another important principle:

Use CSS whenever CSS is sufficient.

Do not write JavaScript for something the browser can already do efficiently.

7.10 Add a Header Scroll State

If you want the header to change appearance after scrolling, JavaScript can add a class.

const header = document.querySelector('.site-header');

if (header) {

    window.addEventListener('scroll', () => {

        if (window.scrollY > 20) {
            header.classList.add('scrolled');
        } else {
            header.classList.remove('scrolled');
        }

    });

}

Then CSS:

.site-header.scrolled {
    box-shadow: var(--shadow-sm);
}

The result is a subtle visual change after the visitor begins scrolling.

7.11 Create a Simple Tabs Component

Suppose your resource page has categories:

Nutrition

Movement

Habits

You can create tabs.

HTML:

<div class="tabs">

    <div class="tab-buttons" role="tablist">

        <button
            class="tab-button active"
            type="button"
            role="tab"
            aria-selected="true"
            data-tab="nutrition">
            Nutrition
        </button>

        <button
            class="tab-button"
            type="button"
            role="tab"
            aria-selected="false"
            data-tab="movement">
            Movement
        </button>

        <button
            class="tab-button"
            type="button"
            role="tab"
            aria-selected="false"
            data-tab="habits">
            Habits
        </button>

    </div>

    <div class="tab-panel active" data-panel="nutrition">
        Nutrition resources go here.
    </div>

    <div class="tab-panel" data-panel="movement">
        Movement resources go here.
    </div>

    <div class="tab-panel" data-panel="habits">
        Healthy habit resources go here.
    </div>

</div>

JavaScript:

const tabButtons = document.querySelectorAll('.tab-button');
const tabPanels = document.querySelectorAll('.tab-panel');

tabButtons.forEach(button => {

    button.addEventListener('click', () => {

        const target = button.dataset.tab;

        tabButtons.forEach(item => {
            item.classList.remove('active');
            item.setAttribute('aria-selected', 'false');
        });

        tabPanels.forEach(panel => {
            panel.classList.remove('active');
        });

        button.classList.add('active');
        button.setAttribute('aria-selected', 'true');

        const panel = document.querySelector(
            `[data-panel="${target}"]`
        );

        if (panel) {
            panel.classList.add('active');
        }

    });

});

This is a reusable component.

7.12 Add Search Functionality

A blog template may contain a search field.

HTML:

<form class="search-form" role="search">
    <label for="site-search">
        Search articles
    </label>

    <input
        type="search"
        id="site-search"
        placeholder="Search...">

    <button type="submit">
        Search
    </button>
</form>

For a static template, JavaScript can provide a simple client-side demonstration.

For example, if article cards have a class:

<article class="article-card">

you can filter them.

const searchForm = document.querySelector('.search-form');
const searchInput = document.querySelector('#site-search');
const articles = document.querySelectorAll('.article-card');

if (searchForm && searchInput && articles.length) {

    searchForm.addEventListener('submit', (event) => {

        event.preventDefault();

        const query = searchInput.value
            .trim()
            .toLowerCase();

        articles.forEach(article => {

            const content = article.textContent.toLowerCase();

            article.hidden =
                query !== '' && !content.includes(query);

        });

    });

}

This is useful for a demo.

A production WordPress template would normally use WordPress’s search system instead.

7.13 Create a Search Empty State

If no articles match, display a message.

HTML:

<p class="search-empty" hidden>
    No articles found. Try another search term.
</p>

JavaScript:

const emptyMessage =
    document.querySelector('.search-empty');

function updateSearchResults() {

    let visibleCount = 0;

    articles.forEach(article => {

        if (!article.hidden) {
            visibleCount++;
        }

    });

    if (emptyMessage) {
        emptyMessage.hidden = visibleCount !== 0;
    }

}

Call the function after filtering.

This creates a more professional experience.

7.14 Add Form Validation

HTML already provides basic validation.

For example:

<input
    type="email"
    required>

The browser checks whether the field is filled and resembles an email address.

JavaScript should add value only where necessary.

For example, you can display a custom message:

const newsletterForm =
    document.querySelector('.newsletter-form');

if (newsletterForm) {

    newsletterForm.addEventListener('submit', (event) => {

        const email =
            newsletterForm.querySelector('input[type="email"]');

        if (!email || !email.value.trim()) {
            event.preventDefault();
            email?.focus();
        }

    });

}

Do not make validation unnecessarily complicated.

7.15 Create a Success Message

For a static demonstration, you might show a success state:

<p class="form-success" hidden>
    Thank you for subscribing.
</p>

JavaScript:

if (newsletterForm) {

    newsletterForm.addEventListener('submit', (event) => {

        event.preventDefault();

        const success =
            newsletterForm.querySelector('.form-success');

        if (success) {
            success.hidden = false;
        }

    });

}

However, remember that this does not actually subscribe anyone.

A commercial template should clearly document that the buyer must connect the form to a real email service or backend.

7.16 Create a Modal

A modal can be useful for:

  • Newsletter signup.
  • Resource downloads.
  • Contact forms.
  • Video previews.

HTML:

<div
    class="modal"
    id="resource-modal"
    hidden>

    <div class="modal-overlay"></div>

    <div
        class="modal-content"
        role="dialog"
        aria-modal="true"
        aria-labelledby="modal-title">

        <button
            class="modal-close"
            type="button"
            aria-label="Close dialog">
            ×
        </button>

        <h2 id="modal-title">
            Get the Free Guide
        </h2>

        <p>
            Enter your email address to continue.
        </p>

    </div>

</div>

JavaScript can open and close it.

const modal = document.querySelector('#resource-modal');
const modalClose = document.querySelector('.modal-close');

function openModal() {
    if (modal) {
        modal.hidden = false;
    }
}

function closeModal() {
    if (modal) {
        modal.hidden = true;
    }
}

modalClose?.addEventListener('click', closeModal);

The modal can later be connected to a CTA button.

7.17 Close a Modal With Escape

document.addEventListener('keydown', (event) => {

    if (event.key === 'Escape' && modal && !modal.hidden) {
        closeModal();
    }

});

This creates a familiar interaction pattern.

7.18 Avoid Overusing Popups

Popups can increase conversions in some contexts, but they can also annoy visitors.

Do not automatically show a large popup immediately after page load unless there is a clear reason.

A better approach is to make the popup:

  • Easy to close.
  • Clearly relevant.
  • Mobile-friendly.
  • Accessible.
  • Limited in frequency.

The visitor should always remain in control.

7.19 Create a Simple Calorie Calculator Carefully

A weight-loss template might include a calculator.

However, this requires extra care.

A calculator can be presented as an educational tool, not as medical advice.

For example, inputs might include:

  • Age.
  • Height.
  • Weight.
  • Activity level.

You could calculate an estimated energy requirement using a standard formula.

But the template should include appropriate educational disclaimers and should avoid presenting the result as a guaranteed prescription.

For a commercial demo, it may be better to label it:

Estimated Daily Energy Calculator

rather than:

Your Exact Calorie Requirement

The wording matters.

7.20 Use JavaScript for UI, Not Medical Decisions

This distinction is extremely important.

A website template can provide:

  • Educational calculators.
  • Habit trackers.
  • Progress interfaces.
  • Resource filters.
  • Recipe filters.
  • Content search.

But a generic website should not pretend to diagnose diseases or prescribe individualized medical treatment.

The template should remain educational and customizable.

7.21 Create a Habit Tracker

A simple habit tracker can be an attractive feature.

HTML:

<div class="habit-list">

    <label>
        <input type="checkbox" class="habit-check">
        Drink enough water
    </label>

    <label>
        <input type="checkbox" class="habit-check">
        Take a daily walk
    </label>

    <label>
        <input type="checkbox" class="habit-check">
        Prepare balanced meals
    </label>

</div>

JavaScript:

const habits =
    document.querySelectorAll('.habit-check');

habits.forEach(habit => {

    habit.addEventListener('change', () => {

        habit.parentElement.classList.toggle(
            'completed',
            habit.checked
        );

    });

});

CSS:

.habit-list label.completed {
    text-decoration: line-through;
    opacity: .6;
}

This provides a simple interactive feature without requiring a database.

7.22 Store Simple Preferences Locally

You can use localStorage for simple non-sensitive preferences.

For example:

habit.addEventListener('change', () => {

    const completed =
        Array.from(habits)
            .map(item => item.checked);

    localStorage.setItem(
        'habitProgress',
        JSON.stringify(completed)
    );

});

Then restore the state:

const saved =
    JSON.parse(
        localStorage.getItem('habitProgress') || '[]'
    );

habits.forEach((habit, index) => {

    habit.checked = Boolean(saved[index]);

});

This means the browser can remember the user’s selections.

Do not use local storage for sensitive personal information.

7.23 Add a Progress Indicator

A visual progress indicator can make a habit tracker more engaging.

HTML:

<div class="progress-bar">
    <div class="progress-fill"></div>
</div>

JavaScript:

function updateProgress() {

    const total = habits.length;

    const completed =
        Array.from(habits)
            .filter(item => item.checked)
            .length;

    const percentage =
        total ? (completed / total) * 100 : 0;

    const progress =
        document.querySelector('.progress-fill');

    if (progress) {
        progress.style.width = `${percentage}%`;
    }

}

Call updateProgress() whenever a checkbox changes.

This creates a satisfying visual feedback mechanism.

7.24 Add Lazy Loading to Images

Modern browsers support:

<img
    src="images/article.jpg"
    alt="Healthy meal"
    loading="lazy">

For images lower on the page, lazy loading can reduce initial loading work.

Do not necessarily lazy-load the primary hero image if it is visible immediately.

The main image may benefit from being loaded quickly.

7.25 Handle Broken Images

During template development, image paths may accidentally be incorrect.

A simple JavaScript fallback is possible:

const images =
    document.querySelectorAll('img');

images.forEach(image => {

    image.addEventListener('error', () => {
        image.classList.add('image-error');
    });

});

However, the preferred solution is to fix incorrect paths and ensure that required template assets are included.

Do not rely on error handling to hide missing files.

7.26 Keep JavaScript Modular

As your script grows, avoid creating one enormous function.

Organize functionality logically:

function initNavigation() {
    // navigation
}

function initFAQ() {
    // FAQ
}

function initSearch() {
    // search
}

function initNewsletter() {
    // newsletter
}

function initHabitTracker() {
    // habit tracker
}

Then:

document.addEventListener('DOMContentLoaded', () => {

    initNavigation();
    initFAQ();
    initSearch();
    initNewsletter();
    initHabitTracker();

});

This is much easier to maintain.

7.27 Avoid Global Variables

Instead of creating many global variables:

var menu;
var button;
var modal;
var search;

keep related values inside functions.

This reduces conflicts.

Modern JavaScript provides:

const
let

Use const when a variable does not need reassignment.

Use let when it does.

Avoid var in modern projects unless there is a specific reason.

7.28 Use Event Delegation When Appropriate

If a page contains many similar elements, event delegation can simplify event handling.

For example:

document.addEventListener('click', (event) => {

    const button =
        event.target.closest('[data-action]');

    if (!button) {
        return;
    }

    const action =
        button.dataset.action;

    if (action === 'close') {
        // close component
    }

});

This technique becomes especially useful in larger templates.

7.29 Handle JavaScript Errors Gracefully

A commercial template should not break simply because one optional component is missing.

Use checks:

const modal =
    document.querySelector('#resource-modal');

if (modal) {
    // Modal code
}

This allows the buyer to remove the modal HTML without causing JavaScript errors elsewhere.

That is a small but valuable detail in reusable template development.

7.30 Test Without JavaScript

Turn JavaScript off temporarily.

Ask:

  • Does the content remain readable?
  • Does the navigation still exist?
  • Do important links remain accessible?
  • Does the FAQ still work if using <details>?
  • Does the page remain understandable?

Not every interaction must work without JavaScript, but essential content should not disappear unnecessarily.

7.31 Test the Console

Open the browser developer tools and check the Console.

Look for errors such as:

Uncaught TypeError

or:

Cannot read properties of null

These errors often indicate that your JavaScript expects an element that does not exist.

Fix console errors before delivering the template.

7.32 Test the Mobile Menu Again

Now test:

  1. Desktop navigation.
  2. Mobile menu.
  3. Menu open state.
  4. Menu close state.
  5. Link selection.
  6. Escape key.
  7. Keyboard focus.
  8. Screen resizing.

Resize the browser while the menu is open.

Make sure the navigation does not become trapped in an incorrect state.

7.33 Test the FAQ

Check:

  • Can the user open an answer?
  • Can the user close it?
  • Can the keyboard operate it?
  • Does the page shift naturally?
  • Does only one answer remain open if that is your intended design?

Do not make the FAQ visually attractive at the expense of usability.

7.34 Test Forms

Try:

Empty form

Invalid email

Valid email

Very long email

Mobile screen

Keyboard navigation

The form should respond predictably.

If the template is only a frontend demonstration, clearly document where the buyer must connect the backend or email provider.

7.35 Document Your JavaScript

Add comments where useful.

For example:

// Mobile navigation toggle
function initNavigation() {
    // ...
}

Do not comment every obvious line.

Good comments explain why something is done when the reason is not obvious.

7.36 Create a JavaScript Checklist

Before completing this stage:

  • Mobile navigation works.
  • Menu state is communicated.
  • Escape closes the menu.
  • FAQ works.
  • Search works if included.
  • Forms validate appropriately.
  • Modal opens and closes if included.
  • Habit tracker works if included.
  • Local storage works if included.
  • No console errors.
  • Missing optional elements do not break the script.
  • Keyboard interaction works.
  • Mobile interactions are usable.

Conclusion

JavaScript gives your template life.

But professional JavaScript is not about adding as many effects as possible. It is about creating meaningful interactions that improve the visitor’s experience.

The best commercial template often uses surprisingly little JavaScript because HTML and CSS already provide much of the required functionality.

Use:

HTML for structure.

CSS for presentation.

JavaScript for behavior.

This separation keeps the project clean and makes it easier for buyers to customize.

Your template now has a visual design and interactive functionality. The next challenge is equally important: making the website fast, accessible, search-friendly and technically polished.

That is the focus of the next chapter.

Latest Posts

Don't Miss

SCIENCE ONLINE

To be updated with all the latest news, offers and special announcements.