Skip to content
PeopleForward

Documentation v1.0.0

Documentation

PeopleForward

A staffing and recruitment agency HTML template on Bootstrap 5. This guide explains how it is put together and how to make it your own.

Version
1.0.0
Pages
78 HTML pages
Built with
Bootstrap 5.3.8 and jQuery 4.0.0
Themes
Light and dark, 6 colour schemes
Build step
None: HTML, CSS and JavaScript

Introduction

Thank you for choosing PeopleForward. It is a website template for staffing and recruitment agencies that serve job seekers and employers alike: five home pages, a job board with three listing views and three job page layouts, pages for employers, sectors and branches, a blog, a candidate portal and an agency dashboard, 78 HTML pages in all.

Everything is static HTML, CSS and JavaScript. There is nothing to install or compile: open a page in a browser and it works, from your disk or from any web server. The pages are made to become the templates of a CMS, so each design is one page filled with one sample (see One page per design).

What's included

  • 78 pages, one for each design, each passing the W3C HTML validator with no errors or warnings.
  • Bootstrap 5.3.8 for the grid and components, restyled by one stylesheet, and jQuery 4.0.0 for the theme's scripts. No other plugins.
  • Light and dark themes that follow the visitor's system setting or their choice in the header, and 6 colour schemes of one stylesheet each.
  • Font Awesome Free 7.3.1 icons and the Red Hat Display and Red Hat Text typefaces, self-hosted. Nothing loads from other servers except the maps' tiles, from OpenFreeMap.
  • Maps for any country with MapLibre and OpenFreeMap: no API key, no account and no cost.
  • A candidate portal and an agency dashboard that work in the browser with sample data, ready to be connected to your back end.
  • Commented code: every block of every page is named in a comment, and the stylesheet opens with a table of contents.

This guide follows the template from the outside in: getting it running, the pages, customising it, the components, the portal and the dashboard, then a reference of the CSS, the JavaScript, the images and the sources. If you get stuck, see Support.

Quick start

  1. Unzip the download. The template folder holds the pages, style.css and assets/; documentation/ holds this guide.
  2. Open index.html in your browser. Every page works straight from your disk; only the maps need an internet connection, for their tiles.
  3. Edit the pages in any code editor. There is no build step: save the file and reload the page.
  4. To publish, upload the contents of the template folder to your web host as they are. The pages link to each other and to assets/ with relative paths, so they work in any folder and on any domain.

A local server, if you prefer one

You don't need a server, but any static server works. With Python, run this in the template folder, then open http://localhost:8000/:

Terminal
python3 -m http.server 8000

Editing shared parts

The header, the mobile menu, the footer, the cookie banner and the shared modals repeat on every page, as a CMS would print them. To change one everywhere, use your editor's search and replace across files (Replace in Files in VS Code, Find in Files in Sublime Text). Each block starts with a comment naming it and ends with an end marker, so it is easy to select whole:

HTML
<!-- Footer
============================================= -->
<footer class="site-footer">
  …
</footer><!-- .site-footer end -->

Tip. Pages in sub-folders reach the shared files with ../ (for example ../style.css in jobs/index.html). When you search for a path, leave out the start, as in assets/css/colors/blue.css, so the pages at both levels match.

Files and folders

The template folder, as it is in the download:

Template folder
├── index.html …              29 pages at the top: the home pages, company, help, account and legal pages
├── style.css                 The theme's styles: 45 numbered sections, listed at the top of the file
├── account/                  Candidate portal · 8 pages
├── blog/                     Blog home, archive layouts and the single post · 19 pages
├── case-studies/             Case study archive and the case study page · 2 pages
├── dashboard/                Agency dashboard · 6 pages
├── employers/                Employer profile · 1 page
├── hire-talent/              Services for employers and the service page · 2 pages
├── jobs/                     Job grid, list and map, and the job page in three layouts · 6 pages
├── locations/                Branches with the map, and the branch page · 2 pages
├── sectors/                  Sectors and the sector page · 2 pages
├── team/                     Consultant profile · 1 page
└── assets/
    ├── CREDITS.md            Sources and licences of the fonts, icons, scripts and map data
    ├── favicon.png           The icon in the browser tab
    ├── css/colors/           6 colour schemes, one file each; blue.css is the default
    ├── fonts/                Red Hat Display and Red Hat Text (WOFF2) and their licence, OFL.txt
    ├── img/                  38 images: placeholders that show their size
    ├── js/theme.js           Puts the light / dark choice back before the page paints
    ├── js/functions.js       The theme's scripts, on jQuery
    ├── vendor/bootstrap/     Bootstrap 5.3.8: the CSS and the JavaScript bundle with Popper
    ├── vendor/fontawesome/   Font Awesome Free 7.3.1: the CSS and the web fonts
    ├── vendor/jquery/        jQuery 4.0.0
    ├── vendor/maplibre/      MapLibre GL JS 5.24.0, for the pages with a map
    └── video/                The video (MP4) and its captions (VTT)
  • Keep each page in its folder, or adjust its relative paths when you move it.
  • Don't edit the files in assets/vendor/. They are the libraries as their authors publish them, so any of them can be updated by replacing its folder. Restyle Bootstrap from style.css instead (see CSS).
  • assets/CREDITS.md and the licence files in assets/fonts and assets/vendor must stay with the files they cover.

Before you go live

A checklist for turning the template into your site. Each step links to the part of this guide that explains it.

  1. Replace the images in assets/img and the video in assets/video: the download has placeholders that show the size each slot expects (see Images).
  2. Replace the sample company: the name and logo, phone numbers, addresses, e-mail addresses, social links and the company line in the footer (see Logo and company details).
  3. Connect the forms to your back end, and remove the prototype note from thank-you.html (see Forms).
  4. Pick your colour scheme and remove the demo's Layouts and Colours menus (see Colour schemes and Removing the demo parts).
  5. Write a <title> and a meta description for each page you keep, and remove the pages you don't need from the menus and the sitemap.
  6. Load your analytics or marketing scripts only with the visitor's consent (see Cookie consent), and have legal.html written for your business. If you keep the maps, say in your privacy notice that the map tiles come from OpenFreeMap (see Maps).
  7. Connect the candidate portal and the agency dashboard to your data, or remove them (see Agency dashboard and Candidate portal).
  8. Set the browser bar colour (<meta name="theme-color">) and the favicon.
  9. Test on your server, and run the W3C validator on the pages you changed.

All pages

All 78 pages, grouped as the header's menus group them. Under each description are the blocks the page is made of, in order: in the page's source, each block starts with a comment of that name.

Home pages (5)

Home pages: each page, its file and what it shows
PageWhat it shows
Home 1 — Staffing agencyindex.htmlHome 1, for a staffing agency: the Find a job / Hire talent switch on the hero stage, client logos, the two entry points, services, sectors, job tickets, the CV banner, results with a testimonial slider, the team and advice.Hero · Logos · Entry Points · Services · Sectors · Jobs · Results · Team · Insights · Closing Conversion
Home 2 — Job boardhome-2.htmlHome 2, a job board: search with quick filters beside a shift-ticket hero, job categories, new jobs as rows, companies hiring, three steps, an app section with a phone mockup, reviews and advice. Its Find a job menu is a mega menu.Job Board Hero · Browse by Sector · Latest Jobs · Top Employers · How It Works · App Promo · Reviews · Insights · Closing Conversion
Home 3 — For employershome-3.htmlHome 3, for employers: a photo hero with a short staff request form, client logos, a figures band, four services as alternating rows, sector teams, the process, case studies, FAQs and a call band.Employer Hero · Logos · Stats Band · Staffing Solutions · Industries · How It Works · Case Studies · FAQ · Call Band
Home 4 — Photo-ledhome-4.htmlHome 4, photo-led: the header lies over a full-width photo until the page scrolls, with an overlapping search, large figures, a job carousel, a sector mosaic, large quotes, a sector list with hover images and a closing band in the accent colour.Photo Hero · Overlapping Search · Key Figures · Featured Jobs · Sector Mosaic · Big Quotes · Sector List · Insights · Accent Closing Band
Home 5 — Local branchhome-5.htmlHome 5, one branch as the home page: local search, a map card with the address, jobs nearby, the branch team, rating and reviews, community work and local services for employers.Local Branch Hero · Jobs Near You · Local Team · Rating and Reviews · Community Work · Local Employer Services · Closing Conversion

Find a job (8)

Find a job: each page, its file and what it shows
PageWhat it shows
Job gridjobs/index.htmlSearch results as a grid: the search bar, job-type tabs, a filter sidebar (a collapsible panel on phones), job tickets and pagination.Page Title · Search Results · Closing Conversion
Job listjobs/list.htmlSearch results as dense rows, with an inline filter bar and a job alert strip.Page Title · Search Results · Closing Conversion
Job mapjobs/map.htmlJobs grouped by area beside a map; hovering or focusing a job lights up its area on the map.Page Hero · Jobs and Map · Closing Conversion
Salary guidesalary-guide.htmlA weekly pay calculator with holiday pay, guide pay for 24 roles in six sectors and this year's pay growth per sector.Page Title · Pay Calculator · Pay by Sector · Pay Growth · Closing Conversion
Job pagejobs/job.htmlThe page every job opens: the job header, a sticky apply card with the key facts and the consultant, the job's sections, the apply form and similar jobs.Job Header · Job Details · Similar Jobs · Closing Conversion
Job page, bannerjobs/job-banner.htmlThe job page in its second layout: a photo banner, a sticky apply bar, fact tiles, one centred column, the employer, the consultant and a similar-jobs carousel.Job Banner · Apply Bar · Job Details · Apply Form · Similar Jobs · Closing Conversion
Job page, summaryjobs/job-summary.htmlThe job page in its third layout: a sticky summary card beside content cards, in-page section navigation and similar jobs as rows.Breadcrumb Bar · Job Details · Apply Form · Similar Jobs · Closing Conversion
Upload your CVupload-cv.htmlRegistration with a CV: details, the work wanted and a file upload.Page Title · Registration Form

Hire talent (8)

Hire talent: each page, its file and what it shows
PageWhat it shows
Hire talenthire-talent/index.htmlServices for employers: client logos, the services, why the agency, how it works, client stories, fees as three price cards and FAQs.Page Title · Logos · Services · Why PeopleForward · How It Works · Client Stories · Fees · FAQ · Closing Conversion
Service pagehire-talent/service.htmlThe page every service opens, filled with Temporary staffing: figures, what's included, the process, a case study, FAQs and the other services.Page Title · Key Figures · What's Included · How It Works · Case Study · FAQ · Other Services · Closing Conversion
Request staffrequest-staff.htmlA staff request form in three parts, beside what happens next.Page Title · Request Form
Employer profileemployers/employer.htmlThe page every employer opens: a cover photo, the company card, open jobs, why people work there, what their workers say, facts at a glance and the consultant.Employer Header · Employer Details · Closing Conversion
Case studiescase-studies/index.htmlEvery case study, with figures, under a photo page title.Page Title · Key Figures · All Case Studies · Closing Conversion
Case studycase-studies/case-study.htmlThe page every case study opens: results, the client's brief, the approach in four steps, a client quote and the service behind it.Page Title · Results · The Story · Our Approach · Client Quote · The Service · More Case Studies · Closing Conversion
Sectorssectors/index.htmlThe six sectors as cards, and why specialist teams matter.Page Title · All Sectors · Why Specialists · Closing Conversion
Sector pagesectors/sector.htmlThe page every sector opens, filled with Logistics & Warehousing: an overview, what it offers job seekers and employers, its jobs, its specialist and the other sectors.Page Title · Sector Overview · For Both Audiences · Sector Jobs · Sector Specialist · Other Sectors · Closing Conversion

About and contact (11)

About and contact: each page, its file and what it shows
PageWhat it shows
About 1 — Storyabout.htmlAbout 1: a photo page title, figures, the story with the video, values, a timeline, the leadership team and accreditations.Page Title · Key Figures · Our Story · Our Values · Milestones · Leadership · Accreditations · Closing Conversion
About 2 — Collageabout-2.htmlAbout 2: a photo collage hero, the mission, numbers, three promises, team cards, a branch map strip and accreditations.Collage Hero · Mission Statement · Numbers · Three Promises · Our People · Branch Map Strip · Accreditations · Closing Conversion
About 3 — Impactabout-3.htmlAbout 3: a photo title with the film, the two audiences, the year's impact as progress bars on navy, a letter from the founder, four working habits and awards.Page Title · Two Audiences · Impact · Founder Letter · How We Work · Awards · Closing Conversion
Consultant profileteam/consultant.htmlThe public profile every consultant opens: portrait, figures, specialisms and languages, live jobs and reviews.Consultant Header · Profile · Live Jobs · Reviews · Closing Conversion
Work for uswork-for-us.htmlCareers at the agency: life there, what staff say and open roles.Page Title · Life at PeopleForward · In Their Words · Open Roles · Closing Conversion
Sustainabilitysustainability.htmlImpact in numbers, three commitments and targets.Page Title · Impact in Numbers · Three Commitments · Targets · Closing Conversion
Contact 1 — Form and mapcontact.htmlContact 1: three ways to get in touch, the form beside the head office card and map, and quick answers.Page Title · Ways to Get in Touch · Contact Form · FAQ
Contact 2 — Departmentscontact-2.htmlContact 2: a card per department with its number, address and hours, the form beside the opening hours, and the branches beside the map.Page Title · Departments · Message and Opening Hours · Branches · Closing Conversion
Contact 3 — Splitcontact-3.htmlContact 3: the details on a navy panel beside a form that starts with topic pills, the head office on the map, and FAQs.Contact Split · Head Office · FAQ
Brancheslocations/index.htmlAll branches as cards beside a map whose pins open the branch page.Page Title · All Branches · Closing Conversion
Branch pagelocations/branch.htmlThe page every branch opens, filled with Leeds: address, hours and a street map with directions, the local team, the branch's jobs and the branches nearby.Branch Header · Branch Details · Local Team · Branch Jobs · Nearby Branches · Closing Conversion

Candidate portal (8)

Candidate portal: each page, its file and what it shows
PageWhat it shows
Overviewaccount/index.htmlThe portal's overview: this week's shifts, figures (shifts, next payday, applications, holiday left), what to do, applications, the consultant and saved jobs.Page Title · Key Figures · Shifts and To-dos · Applications and Consultant · Saved Jobs
Applicationsaccount/applications.htmlEvery application with its stages, next step and history; status filters and Withdraw.Page Title · Application List
Saved jobsaccount/saved-jobs.htmlThe jobs bookmarked anywhere on the site, as tickets.Page Title · Saved Jobs
Job alertsaccount/alerts.htmlJob alerts to create, pause, edit and delete.Page Title · Alerts
Shiftsaccount/shifts.htmlShift offers to take or turn down, the booked shifts with directions, and when the worker can work.
Timesheets and payaccount/timesheets.htmlThis week's timesheet with live totals, payslips, the tax year so far and holiday requests.Page Title · Pay Figures · Timesheet and Holiday
Documentsaccount/documents.htmlThe checks the agency needs, the worker's files with an upload form, and papers from the agency.
Settingsaccount/settings.htmlPersonal details, the work wanted and contact choices; download the account's data or delete the account.Page Title · Settings Form · Your Data

Agency dashboard (6)

Agency dashboard: each page, its file and what it shows
PageWhat it shows
Overviewdashboard/index.htmlThe dashboard's overview: stat tiles for the last 30 days, CVs per week, the hiring pipeline, the latest CVs, tasks, interviews coming up, CV sources, what needs attention and open vacancies.Page Title · Key Figures · CVs per Week and Pipeline · Latest CVs and Tasks · Coming Up, Sources and Alerts · Open Vacancies
Candidatesdashboard/candidates.htmlThe CV inbox: everyone who applied, with their status, right-to-work check and consultant; status filters, search and a sector menu.Page Title · Candidate List
Candidate profiledashboard/candidate.htmlThe profile every candidate opens: stages, CV details, experience and skills, the CV file, the checks before work starts, the next interview, tasks and notes.Page Title · Profile Header · Profile
Tasks and notesdashboard/tasks.htmlThe team's tasks, grouped by when they're due (add, edit, tick, filter, delete), and the notice board of notes.Page Title · Tasks · Notes
Consultant profiledashboard/profile.htmlThe signed-in consultant's profile: figures, targets, candidates, vacancies and contact details.Page Title · Profile Header · Key Figures · Work and Details
Edit profiledashboard/profile-edit.htmlEdit profile: details, introduction, specialisms, a new photo and where they are today; saved changes show across the dashboard.Page Title · Profile Form

Blog (19)

Blog: each page, its file and what it shows
PageWhat it shows
Blog homeblog/index.htmlThe blog home: category tabs, a featured post, a grid of posts and the newsletter.Page Title · Articles · Newsletter · Closing Conversion
Large image, right sidebarblog/large-image.htmlPosts with large images, sidebar on the right.Page Title · Posts · Closing Conversion
Large image, left sidebarblog/large-image-left-sidebar.htmlPosts with large images, sidebar on the left.Page Title · Posts · Closing Conversion
Large image, no sidebarblog/large-image-no-sidebar.htmlPosts with large images in one centred column.Page Title · Posts · Closing Conversion
Medium image, right sidebarblog/medium-image.htmlPosts with the image beside the text, sidebar on the right.Page Title · Posts · Closing Conversion
Medium image, left sidebarblog/medium-image-left-sidebar.htmlPosts with the image beside the text, sidebar on the left.Page Title · Posts · Closing Conversion
Medium image, no sidebarblog/medium-image-no-sidebar.htmlPosts with the image beside the text, without a sidebar.Page Title · Posts · Closing Conversion
Grid, two columns and a sidebarblog/grid-sidebar.htmlA grid of post cards in two columns beside the sidebar.Page Title · Posts · Closing Conversion
Grid, three columnsblog/grid-3-columns.htmlA grid of post cards in three columns.Page Title · Posts · Closing Conversion
Grid, four columnsblog/grid-4-columns.htmlA grid of post cards in four columns.Page Title · Posts · Closing Conversion
Masonry, two columns and a sidebarblog/masonry-sidebar.htmlMasonry in two columns beside the sidebar, with pull quotes among the posts.Page Title · Posts · Closing Conversion
Masonry, three columnsblog/masonry-3-columns.htmlMasonry in three columns, with pull quotes among the posts.Page Title · Posts · Closing Conversion
Masonry, four columnsblog/masonry-4-columns.htmlMasonry in four columns, with pull quotes among the posts.Page Title · Posts · Closing Conversion
Timeline, full widthblog/timeline.htmlThe posts on a two-sided timeline, by month.Page Title · Posts · Closing Conversion
Timeline, with a sidebarblog/timeline-sidebar.htmlThe posts on a one-sided timeline beside the sidebar.Page Title · Posts · Closing Conversion
Post, right sidebarblog/post.htmlThe page every post opens: the article with its sidebar on the right, tags, sharing, the author, the previous and next posts, threaded comments, a comment form and related posts.Article Header · Article · Related Advice · Closing Conversion
Post, left sidebarblog/post-left-sidebar.htmlThe post with its sidebar on the left.Article Header · Article · Related Advice · Closing Conversion
Post, no sidebarblog/post-no-sidebar.htmlThe post without a sidebar.Article Header · Article · Related Advice · Closing Conversion
Post, full-width photoblog/post-image.htmlThe post with its photo full width behind the title.Article Header · Article · Related Advice · Closing Conversion

Help, account and the rest (13)

Help, account and the rest: each page, its file and what it shows
PageWhat it shows
Temporary worktemporary-work.htmlTemporary work explained: why temp with the agency, getting started, timesheets and pay, temporary jobs and FAQs.Page Title · Why Temp With Us · Getting Started · Timesheets & Pay · Temporary Jobs · FAQ · Closing Conversion
FAQfaq.htmlAnswers in four topics as accordions, with a card per topic that jumps to its questions.Page Title · Topics · Questions and Answers · Closing Conversion
Sign inlogin.htmlSign in. Its notes for #reset-sent, #account-created and #account-deleted show when the address ends with them.
Create an accountregister.htmlCreate an account as a job seeker or an employer (Bootstrap pills switch the two forms).
Reset your passwordforgot-password.htmlReset a password; the form comes back to login.html#reset-sent.
Coming sooncoming-soon.htmlA countdown to the launch date and a notify form, without header or footer.
Maintenancemaintenance.htmlProgress and what still works during maintenance, without header or footer.
Page not found404.htmlPage not found, with a job search and links onwards.
Form confirmationthank-you.htmlThe confirmation the site's forms open. Remove its prototype note once your forms send data.
Legal and policieslegal.htmlThe privacy notice, cookie policy, terms, accessibility statement and modern slavery statement, each a section of one page.Page Title · Legal Text
Sitemapsitemap.htmlEvery page, grouped.Page Title · All Pages
Elementselements.htmlThe style guide: every component in numbered groups, each with the classes that build it.
Typographytypography.htmlThe typefaces, type scale, text styles, inline text, lists, quotes, tables and long-form text.Page Title · Index · Typefaces · Type scale · Text styles · Inline text · Lists · Quotes and notes · Tables · Long-form text · Closing Conversion

One page per design

A CMS shows every job, every sector and every post with one template. The pages work the same way: each kind of item has one page, filled with one sample, and every link to an item of that kind opens it. Build each design once and fill it from your data.

Template pages and the sample each one shows
ItemPageSample
Jobjobs/job.htmlWarehouse Operative
Sectorsectors/sector.htmlLogistics & Warehousing
Branchlocations/branch.htmlPeopleForward Leeds
Servicehire-talent/service.htmlTemporary staffing
Case studycase-studies/case-study.html210 pickers in 19 days for peak
Employeremployers/employer.htmlNorthgate Logistics
Consultantteam/consultant.htmlChloe Hartley
Blog postblog/post.htmlSeven interview questions you will almost certainly be asked — and how to answer them
Candidate (dashboard)dashboard/candidate.htmlTomasz Nowak
Consultant (dashboard)dashboard/profile.htmlChloe Hartley
  • Layout variants are separate pages: the job page in three layouts (jobs/job.html, jobs/job-banner.html, jobs/job-summary.html) and the post in four (blog/post.html and the blog/post-*.html pages). In a CMS, the layout becomes a setting for every job or post.
  • Job-type tabs and blog categories open their one archive page; point them at your filtered views.
  • The policies are sections of legal.html. The footers link to four of them by anchor (#privacy, #cookies, #terms and #accessibility); the modern slavery statement (#modern-slavery) is reached from the page's own contents list.

Anatomy of a page

Every page of the site has the same frame (the dashboard, the portal and the launch pages have their own, described below). The order of the stylesheets and scripts matters: Bootstrap first, then style.css, which restyles it, then the colour scheme, which sets the brand colours.

The head

HTML
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">

  <!-- Document Title
  ============================================= -->
  <title>About us — PeopleForward</title>
  <meta name="description" content="PeopleForward has helped people into work since 2009. Meet the team behind 14 branches and 12,800 placements a year.">

  <!-- Browser colours: address bar tint, and native controls in light or dark -->
  <meta name="theme-color" content="#1f4be0">
  <meta name="color-scheme" content="light dark">
  <link rel="icon" href="assets/favicon.png" type="image/png">

  <!-- Font Icons: Font Awesome Free, self-hosted -->
  <link rel="stylesheet" href="assets/vendor/fontawesome/css/all.min.css">

  <!-- Bootstrap: the stock framework file; style.css below restyles it -->
  <link rel="stylesheet" href="assets/vendor/bootstrap/css/bootstrap.min.css">

  <!-- Core Style -->
  <link rel="stylesheet" href="style.css">

  <!-- Colour Scheme: one file from assets/css/colors/; point the link at another to recolour the theme -->
  <link rel="stylesheet" href="assets/css/colors/blue.css" id="color-scheme">

  <!-- Theme Restore: puts back the visitor's light / dark choice, and the demo's colour scheme, before the first paint -->
  <script src="assets/js/theme.js"></script>
</head>
  • theme.js sits at the end of <head>, so the dark theme is in place before anything is painted.
  • Pages in sub-folders start their paths with ../.
  • Every page has its own <title> and a meta description; the layout variants of one design share their design's description.

The body

The blocks of a page, in order
BlockWhat it is
Skip linkThe first tab stop; it jumps past the header to <main id="main">.
Announcement BarA short message with a link, above the header (.announce).
HeaderThe logo, the menus (.site-nav), the theme switch, Sign in, Upload CV, the main call to action and the menu button.
Mobile MenuThe menu below 992px: a Bootstrap offcanvas (#mobile-menu).
ContentThe page itself: <main id="main">, one block after another.
FooterOne of the nine footers.
Cookie ConsentThe cookie banner, hidden until the script shows it.
ModalsSign in and cookie settings on every page, then the page's own (the video, quick apply, the newsletter).
Demo Colour SwitcherDemo only: the Colours menu.
Demo Layout SwitcherDemo only: the Layouts menu.
Toast and Back to TopThe one toast every message uses, and the back-to-top button.
JavaScriptsjQuery, Bootstrap's bundle and functions.js (and MapLibre on pages with a map).

Scripts

HTML
<!-- JavaScripts
============================================= -->
<!-- jQuery first: Bootstrap's bundle (with Popper) then registers its jQuery plugins -->
<script src="assets/vendor/jquery/jquery.min.js"></script>
<script src="assets/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>

<!-- Theme Functions: theme memory, colour switcher, scroller controls, cookie banner, toasts, the pay calculator, the maps and the dashboard -->
<script src="assets/js/functions.js"></script>

Pages with a map load MapLibre between Bootstrap and functions.js:

HTML
<!-- Map Library: MapLibre GL JS, only on pages with a map -->
<script src="../assets/vendor/maplibre/maplibre-gl.js"></script>

Pages with a layout of their own

  • The pages in dashboard/ and account/ replace the site's header and footer with a sidebar (#dash-nav, a Bootstrap offcanvas below 992px) beside a top bar (.dash-top) and the content.
  • coming-soon.html and maintenance.html have no header or footer.

Logo and company details

The logo is text and an icon, so it is sharp at any size and follows the colour scheme. Its tile is the primary colour with an accent dot.

HTML
<a class="navbar-brand brand" href="index.html" aria-label="PeopleForward, home">
  <span class="brand__mark" aria-hidden="true"><i class="fa-solid fa-angles-right"></i></span>
  <span class="brand__name">People<span>Forward</span></span>
</a>
  • It appears in the header, the mobile menu, the footer (with brand--light on dark footers), the dashboard sidebar and top bar, and the launch pages. Change the name everywhere with a search across files for People<span>Forward</span>.
  • The <span> inside .brand__name takes the primary colour; drop it for a single-colour name.
  • To use an image instead, put it inside the link in place of the two spans, and keep the link's aria-label with your company's name:
HTML
<a class="navbar-brand brand" href="index.html" aria-label="Your Company, home">
  <img src="assets/img/logo.png" width="180" height="40" alt="">
</a>
CSS
.brand img {
  width: auto;
  height: 2.25rem;
}

Favicon and browser colour

Each page links assets/favicon.png with <link rel="icon">. Replace the file with your own (a square PNG, 512 × 512 pixels or more), and set <meta name="theme-color">, the colour of the browser bar on phones, to your primary colour.

Sample details to replace

The sample company's details
DetailSampleWhere
Company namePeopleForward, PeopleForward Recruitment LtdEvery page: the logo, the titles and the copyright line
Phone numbers0113 496 0123 and others, as tel:+441134960123 in the linksThe mobile menu, the footer, contact cards and branches. They come from the ranges Ofcom keeps for drama, so they ring nowhere.
E-mail addresseshello@envato.com and other addresses at envato.comThe footer, contact pages, profiles and the sample data
Head office3 Park Square East, Leeds LS1 2NEThe footer, the contact pages and the branch page
Company lineRegistered in England No. 09876543The bottom bar of the footers
Social linksThe home pages of LinkedIn, Facebook and InstagramThe bottom bar of the footers

Important. All people, companies, figures, jobs and reviews in the template are made up. Replace them before you publish.

Colour schemes

The template comes in 6 colour schemes. A scheme is one small stylesheet that sets the brand colours, a primary colour and an accent; everything else, from navy and the greys to the status colours, is shared.

The colour schemes
SchemeFilePrimaryAccent
Blue (default)assets/css/colors/blue.css#1f4be0#ff6b4a
Violetassets/css/colors/violet.css#6a35d9#f571a4
Crimsonassets/css/colors/crimson.css#b20d43#f8bd40
Orangeassets/css/colors/orange.css#a13b00#55c6f4
Greenassets/css/colors/green.css#006a3a#b5ed60
Tealassets/css/colors/teal.css#006565#ffb346

Choosing a scheme

Every page links one scheme, right after style.css:

HTML
<link rel="stylesheet" href="assets/css/colors/blue.css" id="color-scheme">
  1. Search all pages for colors/blue.css and replace it with the file you want, such as colors/teal.css.
  2. Set <meta name="theme-color"> on every page to the scheme's primary colour.

style.css also holds the default scheme's values, so the theme keeps its colours if the link is ever removed.

What a scheme sets

The brand tokens only: --c-primary, --c-primary-fill, --c-primary-hover, --c-tint, --c-tint-fill, --c-map-edge, --c-accent, --c-accent-hover, --c-accent-soft, --c-accent-ink, --c-accent-light, --c-glow, --c-glow-soft, --bs-primary-rgb. The tokens that differ in the dark theme hold both values in light-dark(); see Design tokens for what each one does.

Making your own

  1. Copy blue.css to a new file in assets/css/colors/, for example brand.css.
  2. Change the values. --c-primary-fill carries white text, --c-primary is the text and link colour (lighter in the dark theme), --c-accent carries navy text, and --bs-primary-rgb is the primary fill as three numbers, for Bootstrap's utilities.
  3. Keep text readable: at least 4.5:1 for white on --c-primary-fill, navy (#0c1838) on --c-accent, --c-primary on white, on the grey surface and on the tint, and the dark values on the dark surfaces. The shipped schemes keep white on the primary fill at 6.6:1 or more, so translucent white text on primary bands still reaches 4.5:1.
  4. Repeat the light values in the file's @supports not block, for browsers without light-dark().
  5. Point the pages' #color-scheme link at the new file.

Note. The Colours button in the demo previews the schemes. It is not part of the theme; see Removing the demo parts.

Light and dark theme

  • The colour tokens that change with the theme hold a light and a dark value in light-dark(), and color-scheme picks one. With nothing chosen, the page follows the visitor's system setting.
  • The sun / moon button in the header is two radio inputs read with :has(), so it works without JavaScript and from the keyboard (Tab, then the arrow keys).
  • functions.js remembers the choice in localStorage (pf-theme), and theme.js puts it back as data-theme on <html> before anything is painted, together with Bootstrap's data-bs-theme, so Bootstrap's components follow it.
  • The primary and accent fills and the text on them keep their colours in both themes, and the navy panels only turn a deeper blue, so buttons and bands read the same way.
HTML
<fieldset class="theme-switch">
  <legend class="visually-hidden">Colour theme</legend>
  <input class="visually-hidden" type="radio" name="theme" id="theme-light" value="light" aria-label="Light theme"><label for="theme-light" title="Switch to light theme"></label>
  <input class="visually-hidden" type="radio" name="theme" id="theme-dark" value="dark" aria-label="Dark theme"><label for="theme-dark" title="Switch to dark theme"></label>
</fieldset>

Starting in dark

Put the attributes on <html> of every page. A visitor's own choice, once made, still wins, and the switch then works through functions.js:

HTML
<html lang="en" data-theme="dark" data-bs-theme="dark">

One theme only

  1. Remove the .theme-switch fieldset from the header of every page, and from the top bar of the dashboard and portal pages.
  2. Put data-theme="light" data-bs-theme="light" (or dark) on <html>, and set <meta name="color-scheme"> to the same word.
  3. Delete the Light / Dark part of theme.js and the Theme Memory section of functions.js, so a choice stored earlier can't override it.

Your own styles in both themes

Use the tokens, and they follow the theme. For a colour of your own, give both values:

CSS
.my-banner {
  background: var(--c-surface);
  color: var(--c-text);
  border-color: light-dark(#d9e2ff, #2a3a72);
}

Note. Browsers without light-dark() (Safari before 17.5, Chrome before 123, Firefox before 120) get the light theme: an @supports not block in style.css gives every token its light value there, and the switch hides itself.

Fonts and type

Two variable fonts from the Red Hat family, self-hosted in assets/fonts under the SIL Open Font License: Red Hat Display (weights 300 to 900) for headings, figures and buttons, and Red Hat Text (300 to 700) for running text. One file per family holds every weight.

CSS
@font-face {
  font-family: "Red Hat Display";
  src: url("assets/fonts/red-hat-display-normal.woff2") format("woff2");
  font-weight: 300 900;
  font-style: normal;
  font-display: swap;
}
Type tokens in style.css
TokenValue
--font-display"Red Hat Display", "Segoe UI", Roboto, Arial, sans-serif
--font-text"Red Hat Text", "Segoe UI", Roboto, Arial, sans-serif
--fs-displayclamp(2.75rem, 1.5rem + 4vw, 4.75rem)
--fs-h2clamp(2rem, 1.45rem + 2.2vw, 3.375rem)
--fs-h3clamp(1.375rem, 1.2rem + 0.6vw, 1.75rem)
--fs-leadclamp(1.0625rem, 1rem + 0.35vw, 1.25rem)
--fs-body1.0625rem
--fs-sm0.9375rem
--fs-xs0.8125rem

Changing the fonts

  1. Put your font files in assets/fonts (WOFF2), with their licence.
  2. Point the two @font-face rules at the top of style.css at them, with their family names and weight ranges.
  3. Set --font-display and --font-text to the new families; every heading and text style follows.
  • The files hold the Latin alphabet. For Cyrillic, Greek, Vietnamese or another script, use files that cover it.
  • The pages don't preload the fonts, because Chrome blocks a font preload on pages opened from the disk. On your server you can add <link rel="preload" href="assets/fonts/red-hat-display-normal.woff2" as="font" type="font/woff2" crossorigin> to the <head> for headings that show a moment sooner.
  • A font service such as Google Fonts works too, but then every visit asks that service for the files; self-hosting keeps visitors' addresses on your server.
  • typography.html shows every style, and the classes that set them.

Icons

Every icon is Font Awesome Free 7.3.1, self-hosted in assets/vendor/fontawesome, so icons work offline and from the disk. The template draws no SVG images of its own: the icons are a web font, and the few other marks (the hero's underline, the theme switch) are CSS.

HTML
<i class="icon fa-solid fa-arrow-right" aria-hidden="true"></i>
<i class="icon icon--sm fa-regular fa-envelope" aria-hidden="true"></i>
<i class="icon icon--sm fa-brands fa-linkedin-in" aria-hidden="true"></i>
  • icon sets the glyph in a square box (1.25rem) so icons line up with text; icon--sm makes it 1rem.
  • fa-solid, fa-regular and fa-brands pick the style. Any icon of the free set works: search the gallery at fontawesome.com and copy its fa-… class.
  • Icons are decoration, so they carry aria-hidden="true". A link or button with only an icon needs a name: aria-label, or a <span class="visually-hidden"> with the words.
  • The Icons group of elements.html shows the theme's interface icons.
  • Select menus sit in a .select wrapper that draws a Font Awesome chevron instead of Bootstrap's arrow (see Forms).

Design tokens

The design is driven by custom properties in section 2 of style.css (Tokens). Change one there and every component that uses it follows. Brand colours are best changed in a colour scheme instead, and type tokens are listed under Fonts and type. The values below are the default Blue scheme's.

Colour tokens
TokenLightDarkUsed for
--c-white#ffffff#10182bPage and card background
--c-surface#f4f6fb#0b1222Grey section background
--c-tint#e9efff#1a2650Pale primary behind chips and selected items; the map's land
--c-tint-fill#e9efffSameThe pale tint in both themes, for hovers on white buttons
--c-primary#1f4be0#8eaaffPrimary colour of text and links
--c-primary-fill#1f4be0SamePrimary fills that carry white text: buttons, bands, the hero stage
--c-primary-hover#173bbdSameHover of the primary fills
--c-navy#0c1838#eef2fbHeadings
--c-deep#0c1838#141f42Navy panels, and the text on accent fills
--c-navy-2#18264f#1f2c57A second navy, for hovers and panels on navy
--c-text#17213d#dde3f0Body text
--c-text-2#4a5470#aeb8cfSecondary text
--c-text-3#626b88#8e98b2Muted text: captions, dates, map labels
--c-line#e1e6f0#263254Hairlines and card borders
--c-line-strong#c8d0e2#36446cField borders and stronger dividers
--c-accent#ff6b4aSameAccent fills: urgent badges, strokes, calls to action
--c-accent-hover#ff5a35SameHover of the accent fills
--c-accent-soft#ffe8e1#3b211dBackground of accent badges
--c-accent-ink#b8341b#ff9e88Text of accent badges; accent-coloured text
--c-accent-light#ffb8a6SameAccent text and icons on navy; on the primary fill (about 4:1), large text and icons only
--c-mint-soft#dcf5ea#11362aBackground of success badges and states
--c-mint-ink#12704b#74dfb1Text of success badges and states
--c-sun-soft#fff1d1#3b2e0eBackground of warning badges and highlighted text
--c-sun-ink#8a5a00#f4c766Text of warning badges and states
--c-map-edge#9fb3f5#3b4f8fMap borders and road casings
--c-glowrgb(255 232 225 / 0.7)rgb(255 107 74 / 0.1)Accent glow in the hero background
--c-glow-softrgb(255 232 225 / 0.55)rgb(255 107 74 / 0.08)Softer glow behind page titles
--c-on-color#ffffffSameText on coloured fills
--c-on-dark-2rgb(255 255 255 / 0.78)SameSecondary text on navy and on the primary fill
Space and layout
TokenValue
--space-xs0.75rem
--space-s1rem
--space-m1.5rem
--space-l2rem
--space-xl3rem
--space-2xlclamp(3rem, 2rem + 3vw, 5rem)
--space-sectionclamp(4.5rem, 3.25rem + 5vw, 8rem)
--gutterclamp(1.25rem, 0.6rem + 2.6vw, 3rem)
--grid-gapclamp(1rem, 0.6rem + 1.2vw, 1.75rem)
--container82rem
--header-h4.75rem
Shape and depth
TokenValue
--radius-s0.625rem
--radius-m0.875rem
--radius-l1.25rem
--radius-xl1.75rem
--shadow-card0 1.5rem 3rem -1.25rem light-dark(rgb(12 24 56 / 0.22), rgb(0 0 0 / 0.55))
--shadow-float0 1.25rem 2.5rem -0.75rem light-dark(rgb(12 24 56 / 0.28), rgb(0 0 0 / 0.6)), 0 0.125rem 0.375rem light-dark(rgb(12 24 56 / 0.06), rgb(0 0 0 / 0.3))
Motion
TokenValue
--ease-outcubic-bezier(0.22, 1, 0.36, 1)
--dur-fast160ms
--dur-base300ms
--dur-slow700ms

Bootstrap's own variables are pointed at these tokens in the Bootstrap Bridge, right after them (see CSS).

Layout and grid

Pages are laid out with Bootstrap's grid: .container, .row and columns. The theme's container is 82rem wide at most, with a fluid gutter at the sides (--gutter: clamp(1.25rem, 0.6rem + 2.6vw, 3rem)).

Sections

Each block of a page is a .section with a container inside and, usually, a section head:

HTML
<section class="section section--surface" aria-labelledby="sectors-why">
  <div class="container">
    <header class="section-head section-head--center">
      <p class="kicker">Why specialists</p>
      <h2 class="t-h2" id="sectors-why">Recruiters who know your world</h2>
      <p class="section-head__text">Specialist teams know the licences, checks and shift patterns that matter — so candidates arrive ready, and employers get people who stay.</p>
    </header>
    …
  </div>
</section>
Section classes
ClassWhat it does
sectionA block with the standard vertical spacing
section--surfaceGrey background (--c-surface)
section--tightLess vertical spacing
section-headKicker, heading and lead text over a block's content
section-head--centerCentres the section head
section-head--actionPuts a link or button beside the heading, on the right
kickerThe small line over a heading
t-h1, t-h2Heading sizes, whatever the heading's level

Card grids

Lists of cards are rows with row-cols-* classes, such as row row-cols-sm-2 row-cols-xl-4, with h-100 on the cards so a row's cards share one height. Most cards are links: the title's link carries stretched-link and covers the whole card.

Breakpoints

Where the layout changes
WidthBootstrap nameWhat changes
576pxsmTwo-column card grids; the header shows its call to action
768pxmdWider grids and split sections
992pxlgThe header shows its menus (the mobile menu below this); sidebars sit beside the content
1200pxxlSign in and Upload CV join the header
  • Phone layouts are checked from 320px up, and no page scrolls sideways at any width.
  • Bootstrap's utilities work as usual: d-none d-lg-block, order-lg-last, visually-hidden, w-100 and the rest.
  • The reveal class on many cards marks them for a scroll-in animation of your own; the template doesn't animate them.

Footers

9 footers, one per page; the dashboard and portal pages, coming-soon.html and maintenance.html have none. Most share the same link lists and bottom bar; the shorter ones (Minimal, Centred, Branches and Photo strip) have a single row of links instead, and Job directory has lists of its own.

The footers and the pages that show them
FooterClassesWhat it isPages
Footer 1 — Columnssite-footerFive columns on navyabout.html, blog/grid-3-columns.html, blog/grid-4-columns.html, blog/grid-sidebar.html and 47 more
Footer 2 — Lightsite-footer site-footer--lightThe same on the page colourhome-5.html
Footer 3 — Minimalsite-footer site-footer--minimalOne rowforgot-password.html, login.html, register.html
Footer 4 — Centredsite-footer site-footer--centredOne centred axis404.html, thank-you.html
Footer 5 — Job alertssite-footer site-footer--splitA sign-up panel beside the linkssalary-guide.html
Footer 6 — Job directorysite-footer site-footer--directorySearches, sectors, cities and the apphome-2.html
Footer 7 — Branchessite-footer site-footer--branchesBranch cards on the primary colourcontact-2.html
Footer 8 — Photo stripsite-footer site-footer--photosSix photos over a compact footerabout-2.html
Footer 9 — Big logosite-footer site-footer--wordmarkLink columns over a giant logoabout-3.html
  • To give a page another footer, copy the whole block, from <!-- Footer to <!-- .site-footer end -->, from a page that shows it.
  • The bottom bar, or the single row, links to the policies in legal.html, and its Cookie settings link opens the cookie modal.
  • The job alerts form sends nothing yet; connect it like the other forms (see Forms).

Page titles

Inner pages open with a .page-hero: a breadcrumb, the <h1>, a lead and, in some variants, an image or a search.

HTML
<!-- Page Title
============================================= -->
<section class="page-hero page-hero--compact" aria-labelledby="page-title">
  <div class="container">
    <div class="row page-hero__inner">
      <div class="col-lg page-hero__content">
        <nav aria-label="Breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item"><a href="index.html">Home</a></li><li class="breadcrumb-item active" aria-current="page">Legal and policies</li></ol></nav>
        <h1 class="t-h1" id="page-title">Legal and policies</h1>
        <p class="page-hero__lead">Our privacy notice, cookie policy, website terms, accessibility statement and modern slavery statement, in one place.</p>
        <p class="updated">Last updated 1 October 2026</p>
      </div>
    </div>
  </div>
</section><!-- .page-hero end -->
Page title variants
ClassLookFor example
page-hero--compactTitle, breadcrumb and lead, no imageblog/grid-3-columns.html, blog/grid-4-columns.html, blog/grid-sidebar.html
page-hero--centerCentred titlecontact-2.html, elements.html, salary-guide.html
page-hero--imageThe title over a photoabout-3.html, case-studies/case-study.html, case-studies/index.html
page-hero--mediaTitle beside a photoabout.html, faq.html, hire-talent/index.html
page-hero--searchTitle with the job search (job listings)jobs/index.html, jobs/list.html
page-hero--jobThe job page's headerjobs/job.html
page-hero--branchThe branch page's header, with its maplocations/branch.html
page-hero--mapThe jobs map's titlejobs/map.html
page-hero--personA portrait beside the title (consultant profile)team/consultant.html

Components

elements.html is the template's style guide: every component in 23 groups, built with the same markup as the pages, each with the classes that build it. Open it beside this guide, and copy a component's markup from its source.

The groups of the Elements page
GroupPartWhat it showsAnchor
01. ColoursBasicsEvery colour is a custom property in style.css, shown here with the values of the default Blue scheme. Theme colours hold a light and a dark value; fixed colours stay the same in both. A colour scheme from assets/css/colors/ sets the brand colours again.elements.html#colours
02. IconsBasicsFont Awesome Free, self-hosted. Any icon from the free set works the same way: an <i> with the icon class, hidden from screen readers.elements.html#icons
03. ButtonsBasicsBootstrap’s buttons in the theme’s colours: the primary colour for the main action, the accent for the urgent one and outlines for the rest.elements.html#buttons
04. Badges and chipsBasicsSmall labels for status, categories and filters.elements.html#badges
05. NavigationBasicsWays around a section: where you are, sibling pages and pages of results.elements.html#navigation
06. FeedbackBasicsMessages for the visitor, from a note on the page to a toast that confirms an action, plus tooltips for icon buttons and progress bars.elements.html#feedback
07. Headings and listsContentThe heading that opens each section, and the lists used across the pages.elements.html#headings
08. Steps and figuresContentProcesses, milestones and numbers, drawn as cards, rows and strips.elements.html#figures
09. AccordionContentFAQs as Bootstrap’s accordion: several answers can be open at once, and the plus turns into a minus.elements.html#accordion
10. CardsContentCards for services, sectors, articles and employers. Most are links: the title link stretches over the whole card.elements.html#cards
11. PeopleContentPortraits stand on a colour block; a consultant without a photo shows initials instead.elements.html#people
12. TestimonialsContentQuotes from candidates and clients, with stars, a tag and an optional photo.elements.html#testimonials
13. JobsRecruitmentJob cards drawn as shift tickets, compact rows for long lists and a slider that swipes, scrolls or steps with its arrows.elements.html#jobs
14. Search and mapRecruitmentSearch bars, the filters sidebar (a collapsible panel on phones) and the branch map, which works for any country.elements.html#search
15. FormsRecruitmentNative validation and Bootstrap’s form controls, selects with the theme’s own menu and search; the choices are Bootstrap’s toggle buttons.elements.html#forms
16. Modals and videoOverlaysBootstrap’s modals for signing in, quick apply, the newsletter and cookie settings, the video lightbox and the cookie banner.elements.html#overlays
17. PricingConversionPricing cards for fees or plans, with the featured one raised and badged.elements.html#pricing
18. Calls to actionConversionBands that close a page and cards for sidebars. The split call to action at the bottom of this page ends most pages.elements.html#calls-to-action
19. Headers, titles and footersLayoutThe header, page title and footer each come in more than one look, and every page uses one of each.elements.html#page-parts
20. BlogContentThe blog’s posts in each archive layout, the sidebar widgets and the comments under a post. Every post links to the single-post page.elements.html#blog
21. ExtrasExtrasThe logo, the save-job toggle, the app screen and the back-to-top button that appears once a page scrolls. The header adds dropdown menus, the light and dark switch and, below 992px, the mobile menu.elements.html#extras
22. DashboardDashboardThe agency dashboard’s parts: stat tiles, a weekly chart with its table, the hiring funnel, candidates with their status and checks, and tasks and notes. On the dashboard the lists are saved in the browser; here they work but nothing is kept.elements.html#dashboard
23. Candidate portalDashboardThe job seeker’s account: figures, applications with their stages, shifts and offers, a payslip, holiday, job alerts with their switch, and files. In the portal the buttons change the account and the browser keeps it; here the parts show without them.elements.html#portal

Buttons

HTML
<a class="btn btn-primary" href="jobs/index.html">Search jobs <i class="icon icon--sm fa-solid fa-arrow-right" aria-hidden="true"></i></a>
<a class="btn btn-accent" href="request-staff.html">Request staff</a>
<a class="btn btn-outline-secondary" href="jobs/index.html">View all jobs</a>
<a class="btn btn-primary btn-sm" href="jobs/index.html">Small</a>

btn-primary for the main action, btn-accent for the urgent one, btn-outline-secondary for the rest; btn-light and btn-outline-light on navy bands and photos, btn-dark (navy) on the accent colour; btn-sm and w-100 for size.

Job ticket

The job card, drawn as a perforated shift ticket. Its bookmark is a checkbox: data-job names the job, and functions.js keeps it saved on every page.

HTML
<article class="card ticket reveal">
  <div class="ticket__top">
    <span class="org-mark org-mark--primary" aria-hidden="true">N</span>
    <span class="badge rounded-pill text-bg-urgent">Urgent</span>
    <label class="save">
      <input class="visually-hidden" type="checkbox" data-job="warehouse-operative-leeds">
      <i class="icon icon--sm save__off fa-regular fa-bookmark" aria-hidden="true"></i>
      <i class="icon icon--sm save__on fa-solid fa-bookmark" aria-hidden="true"></i>
      <span class="visually-hidden">Save Warehouse Operative</span>
    </label>
  </div>
  <h3 class="ticket__title"><a class="stretched-link" href="../jobs/job.html">Warehouse Operative</a></h3>
  <p class="ticket__org">Northgate Logistics</p>
  <p class="ticket__meta"><i class="icon icon--sm fa-solid fa-location-dot" aria-hidden="true"></i>Leeds, LS10</p>
  <ul class="ticket__tags"><li>Temporary</li><li>Days · 6am–2pm</li><li>Weekly pay</li></ul>
  <div class="ticket__foot">
    <p class="ticket__pay">£12.80<span>/hr</span></p>
    <p class="ticket__posted">2 hours ago</p>
  </div>
</article>

Alerts

HTML
<div class="alert alert-info">
  <span class="alert__icon"><i class="icon fa-solid fa-circle-info" aria-hidden="true"></i></span>
  <p><strong>Shift times have changed.</strong> Your Monday shift now starts at 7am instead of 6am.</p>
</div>
<div class="alert alert-warning alert-dismissible">
  <span class="alert__icon"><i class="icon fa-solid fa-triangle-exclamation" aria-hidden="true"></i></span>
  <p><strong>Your right-to-work check expires soon.</strong> Upload a new share code before 30 November to keep working.</p><button class="alert__close" type="button" data-bs-dismiss="alert" aria-label="Close"><i class="icon icon--sm fa-solid fa-xmark" aria-hidden="true"></i></button>
</div>

alert-info, alert-success, alert-warning and alert-danger; alert-dismissible with the close button lets the visitor hide one.

Toast

Every page but the two launch pages has one toast, #site-toast, in a status region. Any button with data-toast shows its text there for four seconds:

HTML
<button class="btn btn-primary" type="button" data-toast="Your changes are saved">Save</button>

Tooltips

For icon-only links; the link still needs its own name for screen readers:

HTML
<a href="tel:+441134960123" aria-label="Call Chloe Hartley" data-bs-toggle="tooltip" data-bs-title="Call Chloe"><i class="icon icon--sm fa-solid fa-phone" aria-hidden="true"></i></a>

Modals

Bootstrap's modals, opened by data-bs-toggle="modal" and data-bs-target. Each trigger is also a link, so it still leads somewhere without script:

HTML
<a class="header-actions__icon d-none d-xl-grid" href="login.html" title="Sign in" data-bs-toggle="modal" data-bs-target="#login-modal"><i class="icon fa-solid fa-user" aria-hidden="true"></i><span class="visually-hidden">Sign in</span></a>

Accordion

The FAQs are Bootstrap's accordion; several answers can be open at once.

HTML
<div class="accordion-item faq__item">
  <h3 class="accordion-header"><button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#job-seekers-1" aria-expanded="false" aria-controls="job-seekers-1">How do I apply for a job?<span class="faq__icon" aria-hidden="true"></span></button></h3>
  <div class="accordion-collapse collapse" id="job-seekers-1">
    <div class="accordion-body faq__answer"><p>Choose a job and send the short form on its page — no cover letter needed. Or upload your CV once and a consultant will match you to new roles as they come in, often before they are advertised.</p></div>
  </div>
</div>

Slider

Carousels are CSS scroll snap: visitors swipe or scroll the row, or tab into it and use the arrow keys, with no script needed (there is no autoplay). The controls under it stay hidden until functions.js wires them to the list named in aria-controls.

HTML
<ul class="scroller" id="results-quotes" aria-label="Testimonials" tabindex="0">
  <li class="scroller__item">…</li>
</ul>
<div class="scroller-nav" hidden>
  <button class="scroller-nav__arrow" type="button" aria-controls="results-quotes" data-step="-1"><i class="icon fa-solid fa-arrow-left" aria-hidden="true"></i><span class="visually-hidden">Previous testimonial</span></button>
  <div class="scroller-nav__dots" aria-hidden="true"></div>
  <button class="scroller-nav__arrow" type="button" aria-controls="results-quotes" data-step="1"><i class="icon fa-solid fa-arrow-right" aria-hidden="true"></i><span class="visually-hidden">Next testimonial</span></button>
</div>

Forms

The forms check what is typed with the browser's own validation (required, type="email" and the like), then open a page. Nothing is sent or stored. Most fields have no name, so they submit nothing; the few that have one (the searches and quick staff request on Home 1, and the radio groups, which need a name to work) only put their values in the address of the page they open.

Where the forms go now
FormsAction
Contact, request staff, CV upload, comments, job alerts, newsletter, applythank-you.html, the confirmation page
Job searchesjobs/index.html
Branch and blog searcheslocations/index.html and blog/index.html
Quick staff request (Home 1, Home 3)request-staff.html, the full form
Sign inaccount/index.html, the candidate portal
Create an accountlogin.html#account-created
Reset passwordlogin.html#reset-sent
Dashboard and portal formsSaved in the browser by functions.js (see Data kept in the browser)

Connecting a form

  1. Give every field a name, and every radio button and checkbox a value (without one, a ticked box sends on).
  2. Set the form's action to your form handler (a script on your server, your CMS's form plugin or a form service) and method="post".
  3. For a file upload, add enctype="multipart/form-data".
  4. Check every field again on the server, and protect the form from spam (a hidden honeypot field, or a captcha).
  5. Remove the prototype note from thank-you.html, or point the form at your own confirmation page.
HTML
<form class="form form-card" action="thank-you.html">
  <input class="form-control" id="rs-email" type="email" autocomplete="email" required>

<!-- becomes -->

<form class="form form-card" action="/send-request.php" method="post">
  <input class="form-control" id="rs-email" name="email" type="email" autocomplete="email" required>

Fields

A field is a .form-field with its label and a Bootstrap control. Select menus sit in a .select wrapper with a chevron icon:

HTML
<div class="col-12 form-field form-field--full"><label for="rs-shift">Shift pattern</label><span class="select"><select class="form-select" id="rs-shift"><option>Days</option><option>Nights</option><option>Evenings and weekends</option><option>Rotating shifts</option><option>Office hours</option><option>Not sure yet</option></select><i class="icon icon--sm select__icon fa-solid fa-chevron-down" aria-hidden="true"></i></span></div>

With script, a select in a .select wrapper opens the theme's own list instead of the browser's, with a search field when it has eight options or more (data-search="true" or "false" on the <select> decides). The <select> stays the field, so the form sends it as before.

Choice chips are Bootstrap's toggle buttons (btn-check with a btn-choice label) in a .choices group:

HTML
<div class="form-field">
  <span class="form-label" id="rs-contract">Type of hire</span>
  <div class="choices" role="radiogroup" aria-labelledby="rs-contract"><input class="btn-check" type="radio" name="contract" id="rs-contract-1" checked><label class="btn btn-choice" for="rs-contract-1">Temporary</label><input class="btn-check" type="radio" name="contract" id="rs-contract-2"><label class="btn btn-choice" for="rs-contract-2">Permanent</label><input class="btn-check" type="radio" name="contract" id="rs-contract-3"><label class="btn btn-choice" for="rs-contract-3">Volume or seasonal</label><input class="btn-check" type="radio" name="contract" id="rs-contract-4"><label class="btn btn-choice" for="rs-contract-4">Not sure yet</label></div>
</div>

Consent boxes, and the file upload:

HTML
<div class="form-check consent"><input class="form-check-input" type="checkbox" id="rs-consent" required><label class="form-check-label" for="rs-consent">I agree to PeopleForward contacting me about this request, as described in the <a href="legal.html#privacy">privacy notice</a>.</label></div>
<div class="file-drop">
  <span class="file-drop__icon"><i class="icon fa-solid fa-arrow-up-from-bracket" aria-hidden="true"></i></span>
  <label for="cv-file"><strong>Choose a file to upload</strong> <span>PDF or Word, up to 5 MB. No CV? Leave it — we can write one together.</span></label>
  <input id="cv-file" type="file" accept=".pdf,.doc,.docx">
</div>

Important. The sign-in, registration and password forms only show the screens. Accounts need your back end: sessions, password hashing and the rest.

Maps

The maps work for any country. They are MapLibre GL JS 5.24.0 (assets/vendor/maplibre, loaded only on the pages with a map) drawing OpenFreeMap's vector tiles of OpenStreetMap data: no API key, no account and no cost. They are recoloured from the theme's tokens, so they follow the dark theme and the colour scheme.

Your places

Each map is a .geo-map holding a list of places, each with its position in decimal degrees. Without the library, WebGL or a connection, that list shows instead of the map.

HTML
<div class="geo-map" role="group" aria-label="Street map around PeopleForward Leeds" data-zoom="15">
  <ul class="geo-map__places"><li><span class="geo-map__pin geo-map__pin--current" data-lat="53.7994" data-lng="-1.5506"><span class="geo-map__label">Leeds</span></span></li></ul>
</div>
  • Places are links (<a class="geo-map__pin" href="…">) or, for the branch the page is about, a <span> with geo-map__pin--current.
  • To find a place's coordinates, right-click it in Google Maps or OpenStreetMap and copy them. A position that isn't in decimal degrees (a typo such as 53,7994) is left off the map, with a warning in the browser console naming it.
  • The map fits itself to its places. data-zoom="15" on the .geo-map opens it on its one place at street level instead.
  • On the jobs map, areas are .geo-map__cluster links with the number of jobs as their text. Hovering or focusing a job lights up its area: the job carries data-area and its cluster data-pin with the same code, and style.css pairs the six sample codes with :has() (section 35). A new area needs a line there.
  • Maps start as they come near the screen, so a map lower down loads nothing until it's needed. The mouse wheel and one finger scroll the page; Ctrl + wheel (⌘ + wheel on a Mac) zooms the map, the mouse drags it, and on a phone two fingers move it.

Settings

At the top of the Maps section of assets/js/functions.js:

JavaScript
var mapStyle = "https://tiles.openfreemap.org/styles/positron";
var mapThemeColors = true;
Map settings
SettingWhereWhat it does
mapStylefunctions.jsThe MapLibre style of every map: another style's URL, or your own copy of OpenFreeMap
data-map-styleOne .geo-mapA style for that map only
mapThemeColorsfunctions.jsfalse keeps the style's own colours on every map (the recolouring is made for OpenFreeMap's styles)
data-map-colors="style"One .geo-mapKeeps the style's own colours on that map
data-zoomOne .geo-mapOpens the map at that zoom on its place

The map's own words are in mapText, for translation:

JavaScript
var mapText = {
  zoomIn: "Zoom in",
  zoomOut: "Zoom out",
  locale: {
    "Map.Title": "Map",
    "CooperativeGesturesHandler.WindowsHelpText": "Use Ctrl + scroll to zoom the map",
    "CooperativeGesturesHandler.MacHelpText": "Use ⌘ + scroll to zoom the map",
    "CooperativeGesturesHandler.MobileHelpText": "Use two fingers to move the map"
  }
};

Your own layers

A started map fires geomap:ready on its .geo-map, with the map, and $(el).data("geoMap") holds it. Theme changes repaint only the style's own layers, so yours keep their colours:

JavaScript
$(document).on("geomap:ready", ".geo-map", function (event, map) {
  // map is the MapLibre map: add your sources, layers or markers here.
});

Directions

The address cards link to a route in Google Maps, which opens in a new tab, or in the Maps app on a phone. The destination is URL-encoded:

URL
https://www.google.com/maps/dir/?api=1&destination=3%20Park%20Square%20East%2C%20Leeds%20LS1%202NE%2C%20United%20Kingdom

Important. Keep the map credit (OpenFreeMap, OpenMapTiles and OpenStreetMap) visible: OpenStreetMap's licence requires it. The tiles come from openfreemap.org, which sets no cookies, but each visitor's browser asks it for them, so it sees their IP address: mention it in your privacy notice, or host the tiles yourself (OpenFreeMap is open source).

Video

A thumbnail opens the video in a Bootstrap modal; functions.js plays it when the modal opens and rewinds it when it closes. Without script, the thumbnail links to the file.

HTML
<div class="col-lg-6"><figure class="media-text__media"><a class="video-thumb" href="assets/video/peopleforward-story.mp4" data-bs-toggle="modal" data-bs-target="#video-modal">
  <img src="assets/img/about-office.webp" width="900" height="1125" loading="lazy" alt="">
  <span class="video-thumb__play"><i class="icon fa-solid fa-play" aria-hidden="true"></i></span>
  <span class="video-thumb__label">Watch: a week in work<span>0:19</span></span>
</a></figure></div>
HTML
<div class="modal modal--video" id="video-modal" tabindex="-1" role="dialog" aria-labelledby="video-modal-title">
  <div class="modal-dialog modal-dialog-centered modal-xl">
    <div class="modal-content">
      <div class="modal-header">
        <h2 class="modal-title visually-hidden" id="video-modal-title">PeopleForward: a week in work</h2>
        <button class="modal-close" type="button" data-bs-dismiss="modal" aria-label="Close"><i class="icon fa-solid fa-xmark" aria-hidden="true"></i></button>
      </div>
      <div class="modal-body">
        <div class="ratio ratio-16x9">
          <video controls playsinline preload="none" src="assets/video/peopleforward-story.mp4">
            <track kind="captions" src="assets/video/peopleforward-story.vtt" srclang="en" label="English">
          </video>
        </div>
      </div>
    </div>
  </div>
</div><!-- #video-modal end -->
  • Replace assets/video/peopleforward-story.mp4 with your video (MP4, H.264) and peopleforward-story.vtt with its captions. The download has a placeholder video of the same size, 960 × 540.
  • Captions are a WebVTT file: a time range, then the text. Keep a <track kind="captions"> for viewers who can't hear the sound.
  • preload="none" keeps the page light: nothing downloads until the visitor plays it.

Cookie consent

The cookie banner shows on every page until the visitor chooses: Accept all, Essential only, or their own choice in the Cookie settings modal, which also opens from every footer. The choice is kept in localStorage as pf-consent.

HTML
<section class="cookie-banner" aria-labelledby="cookie-title" hidden>
  <span class="cookie-banner__icon"><i class="icon fa-solid fa-cookie-bite" aria-hidden="true"></i></span>
  <div class="cookie-banner__body">
    <h2 class="cookie-banner__title" id="cookie-title">Cookies on PeopleForward</h2>
    <p>We use essential cookies to make the site work. With your consent we’d also use analytics cookies to improve it and marketing cookies to show relevant job adverts. <a href="legal.html#cookies">Read our cookie policy</a>.</p>
    <div class="cookie-banner__actions">
      <button class="btn btn-primary btn-sm" type="button" data-consent="all">Accept all</button>
      <button class="btn btn-outline-secondary btn-sm" type="button" data-consent="essential">Essential only</button>
      <button class="cookie-banner__more" type="button" data-bs-toggle="modal" data-bs-target="#cookie-settings">Choose cookies</button>
    </div>
  </div>
</section><!-- .cookie-banner end -->

Loading scripts with consent

The banner only records the choice. Read it before loading an analytics or marketing script:

HTML
<script>
  var consent = null;
  try {
    consent = JSON.parse(localStorage.getItem("pf-consent"));
  } catch (err) {
    // Storage blocked: treat it as no consent.
  }
  if (consent && consent.analytics) {
    // Load your analytics script here.
  }
</script>
  • A choice made on a page takes effect from the next page. To start a script at once, add it to saveConsent() in the Cookie Consent section of functions.js.
  • To add a kind of cookie, add a box with its own data-consent-type (for example preferences) to the settings modal. It is saved with the others.
  • Without script the banner stays hidden, and nothing that needs consent runs either.
  • While the banner shows, functions.js makes room for it at the end of the page from the first Tab, so nothing the keyboard reaches is hidden behind it.

Important. The banner is a tool, not legal advice. What you must ask for, and how, depends on your country and the scripts you use.

Pay calculator and countdown

Pay calculator

The salary guide's calculator works out the week's pay from the hourly rate, the hours and an extra rate for nights or weekends, adds holiday pay, and gives a year's pay. The page is built with the default figures worked out, so it reads right without script.

  • The fields are #calc-rate, #calc-hours, #calc-extra and #calc-extra-hours; the results are the <output> elements #calc-basic, #calc-holiday, #calc-total and #calc-year.
  • Holiday pay is holidayRate in the Pay Calculator section of functions.js: 12.07%, the UK rate for 5.6 weeks of holiday for every 46.4 weeks worked. A year is 52 weeks' pay.
  • Amounts are written by money(), in pounds with British number formatting. For another currency, change the symbol and "en-GB" in money(), and the £ in the field labels and the pre-filled results of salary-guide.html.

Countdown

coming-soon.html counts down to the date in data-countdown, an ISO 8601 date and time with its offset from UTC:

HTML
<div class="countdown" data-countdown="2027-06-01T09:00:00+01:00" hidden><div><span class="countdown__num" data-unit="days">00</span><span class="countdown__unit">days</span></div><div><span class="countdown__num" data-unit="hours">00</span><span class="countdown__unit">hours</span></div><div><span class="countdown__num" data-unit="minutes">00</span><span class="countdown__unit">minutes</span></div><div><span class="countdown__num" data-unit="seconds">00</span><span class="countdown__unit">seconds</span></div></div>
  • Change the date there, and the launch date written above it, which is what screen readers get.
  • Once the date has passed (or if it isn't a date), the countdown stays hidden and the written date remains.

Blog

The blog has a home page, 14 archive layouts and four layouts of the single post, all with the same posts, so any layout can be your blog's.

  • Archives: large images or medium images, each with a right, a left or no sidebar; a grid in two columns beside a sidebar, three or four columns; masonry in the same three, with pull quotes among the posts; and a timeline, two-sided or one-sided beside a sidebar.
  • The single post (blog/post.html, the page every post opens) has tags, sharing, the author, the previous and next posts, threaded comments with the author's replies marked, a comment form and related posts. Its other layouts put the sidebar on the left, leave it out, or show the photo full width behind the title.
  • The sidebar holds a search, categories with counts, recent posts, tags and a job search card.
  • In the post layouts with a sidebar, Get new articles by email opens a newsletter sign-up in a modal (#newsletter-modal).
  • Long text goes in .prose, which styles headings, lists, quotes and tables inside an article.

Agency dashboard

The staff side of the agency, in dashboard/: six pages in a layout of their own (a navy sidebar and a top bar), built from the same tokens and components as the site, so they follow the dark theme and the colour schemes.

  • The figures, charts and candidates are sample data written into the pages.
  • The candidate filters, tasks and notes (added, edited, ticked, pinned, filtered, searched and deleted) and Edit profile work, and keep their changes in the browser until you connect them to your back end.
  • Elements with data-me show the signed-in consultant's saved profile: their text, an image's src or a link's address.
  • The charts are HTML and CSS: each bar's height is a percentage in its --h and each pipeline step's width in --w. The weekly chart has a table of its numbers under it, for keyboard and screen reader users, and the pipeline writes each number beside its bar.

The page's data

Each dashboard page prints the data its scripts need as JSON in <script type="application/json" id="dash-data">. functions.js draws the task and note lists from it, or from localStorage once something has changed. A CMS prints the same JSON from its database. Its shape, cut to one item per list:

JSON
{
  "today": "2026-10-26",
  "me": "priya",
  "candidatePage": "../dashboard/candidate.html",
  "team": {
    "priya": {
      "name": "Chloe Hartley",
      "photo": "../assets/img/consultant-1.webp"
    },
    "james": {
      "name": "James Okoro",
      "photo": "../assets/img/consultant-2.webp"
    }
  },
  "candidates": {
    "grace-mensah": "Grace Mensah",
    "marcus-lee": "Marcus Lee"
  },
  "types": {
    "call": [
      "Call"
    ],
    "email": [
      "Email"
    ]
  },
  "priorities": {
    "high": "High",
    "medium": "Medium"
  },
  "categories": {
    "general": "General",
    "client": "Client"
  },
  "tasks": [
    {
      "text": "Chase Brookfield Care for Grace Mensah’s interview date",
      "due": "2026-10-23"
    }
  ],
  "notes": [
    {
      "author": "leah",
      "at": "2026-10-26T08:05"
    }
  ]
}
The keys of #dash-data
KeyType
todaytext
metext
candidatePagetext
teamobject
candidatesobject
typesobject
prioritiesobject
categoriesobject
taskslist
noteslist
  • today is the date the sample is written for, so its tasks keep their groups (overdue, today, tomorrow) whenever the demo is opened. Print the real date on a live site.
  • A task has id, text, due, priority, type, candidate, assignee and done; a note has id, author, at, category, pinned, candidate and text.
  • To save to your server, replace the saveList() calls in the Tasks and Notes sections of functions.js, and the localStorage.setItem() in Profile, with requests to your API, and print the saved data in #dash-data.

Candidate portal

The job seeker's side, in account/: eight pages in the dashboard's layout, filled with one temporary worker so every page has a history to show. Signing in (the sign-in page and the sign-in window) opens it.

  • Saved jobs, withdrawing an application, job alerts, shift offers and availability, the timesheet with its sums, payslips, holiday requests, uploads and settings all work and are kept in the browser.
  • Settings can download everything kept for the account as a JSON file, and delete the account, which forgets all of it and signs out to login.html#account-deleted.
  • The first visit to the portal brings in the account's saved jobs, as signing in would. An upload keeps only the file's name, kind and size.
  • Elements with data-account show the saved name (name, first or initials).
  • Without script, the buttons that would change something stay hidden and the samples show.

The page's data

Each portal page prints the account's samples and labels as JSON in <script type="application/json" id="portal-data">, cut here to one item per list:

JSON
{
  "today": "2026-10-26",
  "week": "2026-10-26",
  "loginPage": "../login.html",
  "account": {
    "name": "Jade Robinson",
    "email": "jade.robinson@envato.com"
  },
  "saved": [
    "forklift-driver-wakefield"
  ],
  "alerts": [
    {
      "id": "al1",
      "keywords": "Forklift driver"
    }
  ],
  "offers": [
    "sh1"
  ],
  "activeApps": [
    "app-halcyon"
  ],
  "labels": {
    "sectors": {
      "logistics": "Logistics & Warehousing",
      "healthcare": "Healthcare & Social Care"
    },
    "types": {
      "": "Any type",
      "temporary": "Temporary"
    }
  },
  "pay": {
    "rate": 12.8,
    "overtime": 16.2
  },
  "holidayLeft": 51.2,
  "agentFirst": "Chloe"
}
The keys of #portal-data
KeyType
todaytext
weektext
loginPagetext
accountobject
savedlist
alertslist
offerslist
activeAppslist
labelsobject
payobject
holidayLeftnumber
agentFirsttext

On a live site, print this JSON from the signed-in account, send each change to your server from the sections of functions.js that save it (Saved Jobs, Applications, Job Alerts, Shifts, Timesheet, Holiday, Documents and Account), and send uploads to private storage.

Data kept in the browser

The scripts keep the visitor's choices and the portal's and dashboard's changes in the browser, under these keys. Nothing is sent anywhere.

Keys the scripts keep
KeyStoragePartWhat it holds
pf-themelocalStorageEvery pagelight or dark: the header switch's choice. theme.js puts it back before the page paints.
pf-colorsessionStorageDemo onlyThe colour scheme picked in the Colours menu, for the rest of the visit in that tab.
pf-consentlocalStorageEvery pageThe cookie choices, such as {"analytics": true, "marketing": false}.
pf-savedlocalStorageEvery pageThe jobs saved with a bookmark, by the names in their data-job.
pf-taskslocalStorageDashboardThe team's tasks, once one has changed.
pf-noteslocalStorageDashboardThe notes, once one has changed.
pf-profilelocalStorageDashboardThe consultant profile saved on Edit profile, with the photo.
pf-withdrawnlocalStoragePortalThe ids of withdrawn applications.
pf-alertslocalStoragePortalThe job alerts.
pf-shiftslocalStoragePortalThe answers to shift offers, by offer id.
pf-availabilitylocalStoragePortalThe ticked boxes of the availability form.
pf-timesheetlocalStoragePortalThis week's timesheet rows and whether it was sent.
pf-holidaylocalStoragePortalThe holiday requests.
pf-uploadslocalStoragePortalThe name, kind, size and date of each upload (never the file).
pf-accountlocalStoragePortalThe settings: name, contact details and preferences.
  • Storage belongs to the site's address: pages opened from the disk share one, a live site has its own.
  • If storage is blocked (some private windows), everything still works on the page, and the next page starts afresh.
  • To start again while testing, clear the site's data in your browser (in Chrome: Developer tools › Application › Storage › Clear site data).
  • If several sites run on one domain, give the keys a prefix of their own in theme.js and functions.js.

CSS

style.css is the theme's one stylesheet. It loads after Bootstrap's stock bootstrap.min.css and restyles it, so Bootstrap stays unedited and can be updated by replacing its file. It is mobile-first, on Bootstrap's breakpoints, and opens with a table of contents: 45 numbered sections, each split into components by comment dividers.

The sections of style.css
SectionComponents
1. Fonts
2. TokensColour Scheme, Custom Properties, Bootstrap Bridge, Fallback Without light-dark()
3. BaseReset, Reboot Adjustments, Element Defaults, Focus & Selection, Accessibility Helpers, Icons, Stretched Link
4. LayoutContainer & Section, Section Head, Card Grids, Page Layouts
5. TypographyHeadings, Kicker
6. ControlsButtons, Badges
7. Announcement & HeaderAnnouncement Bar, Site Header, Logo, Primary Navigation, Dropdown Panel, Header Actions, Theme Switch, Menu Toggle, Mobile Menu
8. HeroHero Layout, Hero Badge, Title & Brush Mark, Find a Job / Hire Talent Switch, Trust Row, Hero Visual, Floating Cards, Doodles
9. Logos
10. Entry PointsEntry Cards, Check List, Card Actions & Media
11. Services
12. Sectors
13. Jobs (Shift Tickets)Filter Chips, Job Ticket, CV Banner
14. ResultsResults Band, Figures, Testimonials, Testimonial Slider
15. TeamConsultant Cards, Branch Links
16. Insights
17. Closing Conversion
18. FooterFooter Grid, Brand & Contact, Link Columns, Job Alerts, Bottom Bar
19. Inner Pages — Shared StructureShared Modifiers, Breadcrumb, Page Hero, Page Layouts, Split
20. Shared Content BlocksStat Row, Chip List, Check List Variants, Value Cards, Steps, FAQ, Case Study, Media & Text, Light Testimonials, Hire Talent Pages, Sector Overview, Accreditations
21. People and Contact CardsPerson, Contact Card, Side Panel, Mini Steps
22. Search, Filters and ListingsSearch Bar, Job Type Tabs, Filters Panel, Results Bar, Job List, Job Alert Card, Pagination, Save Button
23. Job DetailJob Header, Job Sections, Apply Card, Key Facts, Apply Form Panel
24. FormsForm Layout, Form Card, Form Grid & Fields, Inputs & Selects, Select Menu, Choice Chips, File Upload, Consent, Submit Row
25. Map and BranchesMap Card, Map, Branch Cards
26. Advice and ArticlesFeatured Post, Archive Grid, Newsletter Band, Article Header, Article Image, Prose, Tip Box, Pull Quote, Author Box, Sidebar Call to Action, Share Links
27. Company PagesWeekly Pay Card, Timeline, Job Openings, Table of Contents
28. Confirmation and Error StatesState Message, Next Links, Sitemap
29. Layout Variants — Shared PiecesView Switch, Select in a Search Field, Job Rows, Scroller, Quote Grid, Call Band, Demo Layout Switcher, Demo Colour Switcher
30. Home 2 — Job BoardBoard Hero, Shift Pass, Hero Figures, Sector Tiles, Companies Hiring, App Promo, Phone Mockup
31. Home 3 — EmployersEmployer Hero, Figures Band, Service Rows, Sector Team Chips, Case Study Cards
32. Home 4 — Photo-LedPhoto Hero, Overlapping Search, Large Figures, Sector Mosaic, Quote Split, Sector List, Accent Call Band
33. Home 5 — Local BranchesLocal Hero, Branch Address Card, Rating & Reviews
34. About 2Collage Hero, Mission Statement, Numbers, Promises, Team Cards, Branch Map Strip, Accreditations Grid
35. Jobs — List and Map ViewsFilter Bar, Job Alert Strip, Map View, Area Groups, Mini Job Card, Map Clusters
36. Job Detail — Banner and Summary LayoutsJob Banner, Sticky Apply Bar, Fact Tiles, Employer Box, Consultant Strip, Apply Form Card, Job Top Bar, Summary Card, Section Navigation, Content Cards
37. Help and Style Guide PagesFAQ Topics, Style Guide Index, Style Guide Sections, Colour Swatches, Icon Tiles, Typefaces, Type Scale, Text Colours and Inline Text, Tables
38. Overlays and FeedbackModals, Video Lightbox, Toasts, Tooltips, Alerts, Progress Bars, Cookie Banner, Back to Top
39. Header, Footer and Title VariantsTransparent Header, Mega Menu, Light Footer, Minimal Footer, Footer Link Row, Centred Footer, Job Alerts Footer, Job Directory Footer, Branches Footer, Photo Strip Footer, Big Logo Footer, Page Title Variants
40. Account, Profile and Content PagesPricing Cards, Account Pages, Employer Profile, Consultant Profile, Case Studies, Salary Guide, Coming Soon and Maintenance, Style Guide Additions
41. BlogArchive Layout, Post Meta, Large and Medium Image Posts, Post Cards, Masonry, Timeline, Sidebar Widgets, Single Post, Comments
42. About and Contact VariantsAudience Cards, Impact, Founder Letter, Awards, Departments, Contact Split
43. Agency DashboardDashboard Layout, Dashboard Sidebar, Dashboard Top Bar, Notifications, Dashboard Page Title and Cards, Stat Tiles, Column Chart, Funnel, Dashboard Tables, Status and Checks, Agenda, Tasks, Notes, Candidate Filters, Candidate Profile, Consultant Profile, Edit Profile
44. Candidate PortalPortal Figures, Applications, Shifts, Availability, Timesheet, Payslips, Holiday, Job Alerts, Documents, Settings
45. MotionKeyframes, Animations, Reduced Motion

Restyling Bootstrap

The Bootstrap Bridge, in section 2, points Bootstrap's global variables (--bs-body-color, --bs-link-color, --bs-border-color, --bs-primary and the rest) at the theme's tokens. Each component is then tuned through its own variables, as Bootstrap intends:

CSS
.btn-accent {
  --bs-btn-color: var(--c-deep);
  --bs-btn-bg: var(--c-accent);
  --bs-btn-border-color: transparent;
  --bs-btn-hover-color: var(--c-deep);
  --bs-btn-hover-bg: var(--c-accent-hover);
  --bs-btn-hover-border-color: transparent;
  --bs-btn-active-color: var(--c-deep);
  --bs-btn-active-bg: var(--c-accent-hover);
  --bs-btn-active-border-color: transparent;
}

Adding your own styles

Keep your changes in a stylesheet of your own, linked after the colour scheme, so style.css can be updated without losing them:

HTML
<link rel="stylesheet" href="assets/css/colors/blue.css" id="color-scheme">
<link rel="stylesheet" href="assets/css/custom.css">
  • Use the tokens (var(--c-primary), var(--space-m), var(--radius-m)) so your additions follow the colour schemes and the dark theme.
  • Bootstrap's CSS carries a few small SVG images (the select arrow, checkbox ticks, the accordion chevron, the close button and others). style.css switches off the ones on components the theme uses and draws its own marks; a component you add from Bootstrap's documentation may bring its image back.
  • The stylesheet uses logical properties (margin-inline, inset-inline-start), so it is mostly ready for right-to-left languages, though a right-to-left version isn't included (arrow icons, for one, would need flipping).
  • Motion only plays with prefers-reduced-motion: no-preference. With reduced motion, every animation and transition is cut to almost nothing.

JavaScript

Two files of the theme's own, beside jQuery and Bootstrap's bundle:

  • assets/js/theme.js, a few lines of plain JavaScript at the end of <head>. Before anything is painted it puts back the light / dark choice and the demo's colour scheme, and marks <html> with .js for the styles that need script.
  • assets/js/functions.js, loaded last before </body>, holds the theme's behaviour on jQuery, in one wrapper that receives jQuery as $, so it keeps working if another script calls $.noConflict().

Bootstrap's components (menus, the offcanvas, accordions, tabs, collapses and modals) start from their data-bs-* attributes, as Bootstrap documents them. functions.js adds only the tooltips and the toast, which Bootstrap leaves to the page, and the theme's own parts:

The sections of functions.js, in order
SectionWhat it does and what it looks for
Theme MemoryStores the header switch's light / dark choice and checks the matching radio on every page, also after Back. Hooks: input[name="theme"]; sets data-theme and data-bs-theme on <html>.
Colour SwitcherDemo only. Swaps the file name in <link id="color-scheme"> and keeps the scheme for the visit. Hooks: input[name="color"].
Scroller ControlsAdds arrows and dots to a scroll-snap row and shows them. Hooks: .scroller-nav with two .scroller-nav__arrow buttons (aria-controls names the list, data-step is -1 or 1) and .scroller-nav__dots.
TooltipsStarts Bootstrap's tooltips, without fades. Hooks: [data-bs-toggle="tooltip"] with data-bs-title.
ToastsShows the page's toast (#site-toast) with a message: when a job is saved or removed, and for any button with data-toast="Your message".
Select MenusOpens the theme's own list for a select in a .select wrapper instead of the browser's, with a search field from eight options (data-search="true" or "false" on the select decides). The select stays the field, so forms and scripts read it as before; without popover support the browser's list stays.
Cookie ConsentShows .cookie-banner until a choice is stored, and saves the choices from the banner ([data-consent="all"], [data-consent="essential"]) and from the settings form (.cookie-form, boxes with data-consent-type). From the first Tab it marks <html> with .is-tabbing.
Video LightboxPlays the video in #video-modal when the modal opens and rewinds it when it closes.
Transparent HeaderAdds .is-scrolled to .site-header--transparent once the page scrolls (Home 4).
Back to TopShows .back-to-top after a screen of scrolling; it goes up and gives the keyboard focus to the skip link.
Pay CalculatorWorks out the salary guide's totals as the fields change (.calc__form, the #calc-… fields and outputs). Holiday pay is holidayRate (0.1207); money() formats the amounts.
CountdownCounts down to the date in data-countdown (ISO 8601) into its [data-unit] numbers, and stays hidden once that date has passed.
Dashboard MenuNames the dashboard and portal sidebar (#dash-nav, data-menu-label) while it opens as a panel below 992px.
Dashboard DataReads the JSON in #dash-data and holds the helpers the dashboard shares: lists kept in localStorage, new ids, dates relative to the data's today.
ProfileShows the saved consultant profile in every [data-me] element and runs Edit profile (#profile-form, the photo preview data-preview, [data-profile-reset]).
TasksDraws, filters, adds, edits (#task-modal), ticks and deletes tasks in each [data-task-view] (board, mine or candidate), with the counts in [data-task-count], [data-task-stat] and the sidebar.
NotesThe same for notes in each [data-note-view]: forms with data-note-add, the edit window #note-modal, pinned notes first.
Candidate FiltersNarrows the candidates table with the status buttons ([data-status-filter]), #cand-search and #cand-sector, through each row's data-status, data-search and data-sector.
Saved JobsKeeps the jobs saved with a bookmark (.save input[data-job]) and shows only the saved cards ([data-saved-item]) in a [data-saved-list].
ApplicationsFilters the applications by status ([data-app-filter]) and withdraws one after asking (#withdraw-modal).
Job AlertsCreates, pauses, edits (#alert-modal) and deletes job alerts.
ShiftsTakes or turns down shift offers ([data-shift-take], [data-shift-decline]) and keeps the availability form (#availability-form).
TimesheetWorks out hours, overtime, pay and holiday as the timesheet (#timesheet) is filled in; Save draft, Send for approval and Change it; opens each payslip in #payslip-modal.
HolidayAdds a holiday request from #holiday-modal, takes its hours off what's left, and cancels a request while it waits.
DocumentsLists an uploaded file with its name, kind and size (#upload-form). The file itself stays on the visitor's computer: a real site sends it to its server here.
AccountSaves the settings form (#account-form), shows the name in every [data-account] element, downloads the account's data as JSON and deletes the account.
MapsTurns each .geo-map into a MapLibre map as it nears the screen, recoloured from the theme tokens. Settings at the top of the section: mapStyle, mapThemeColors and mapText.
Demo MenusDemo only. The close buttons inside the Layouts and Colours panels, which give the focus back to the button that opened them.

Without JavaScript

The pages still read and link as they should: the desktop menus open on hover and focus, the theme switch works, the save-job bookmarks tick (without keeping anything), carousels scroll, every trigger of a modal is also a link, maps show their list of places, and the dashboard and portal show their samples. The mobile menu, tabs, accordions and modals need Bootstrap's script, and what only script can do stays hidden: the slider arrows, the cookie banner, the countdown and the buttons that would change data.

Adding your own scripts

Put them in a file of your own after functions.js, so the theme's file can be updated. Bootstrap's components are on jQuery too, as in $("#login-modal").modal("show").

Images

The download holds no photographs. Every file in assets/img is a grey placeholder with the same name and pixel size as the photo in the live preview, showing that size (for example 900 × 600), and the video is a placeholder too. Replace them with your own images and the pages need no changes.

The images, their sizes and where they appear
FileSize (px)ShapePages
about-office.webp900 × 11254:5about-2.html, about.html, forgot-password.html and 2 more
about-team.webp1200 × 8003:2about-2.html, about.html, case-studies/index.html and 1 more
avatar-1.webp240 × 2401:1case-studies/case-study.html, elements.html, hire-talent/index.html and 4 more
avatar-2.webp240 × 2401:1blog/post-image.html, blog/post-left-sidebar.html, blog/post-no-sidebar.html and 5 more
avatar-3.webp240 × 2401:1index.html
avatar-4.webp240 × 2401:1index.html
avatar-5.webp240 × 2401:1blog/post-image.html, blog/post-left-sidebar.html, blog/post-no-sidebar.html and 3 more
avatar-6.webp240 × 2401:1index.html
careers-1.webp900 × 6003:2about-2.html, about-3.html, case-studies/case-study.html and 4 more
careers-2.webp900 × 6003:2about-2.html, blog/grid-3-columns.html, blog/grid-4-columns.html and 6 more
consultant-1.webp600 × 7504:5about-2.html, account/index.html, account/shifts.html and 33 more
consultant-2.webp600 × 7504:5about-2.html, blog/grid-3-columns.html, blog/grid-4-columns.html and 17 more
consultant-3.webp600 × 7504:5about-2.html, blog/grid-3-columns.html, blog/grid-4-columns.html and 24 more
consultant-4.webp600 × 7504:5about-2.html, blog/grid-3-columns.html, blog/grid-4-columns.html and 24 more
entry-candidate.webp900 × 11254:5index.html
entry-employer.webp900 × 11254:5blog/grid-3-columns.html, blog/masonry-3-columns.html, blog/masonry-4-columns.html and 4 more
hero-person.webp817 × 1200Transparent cut-out of a personindex.html
home-2-person.webp800 × 12002:3, Transparent cut-out of a personhome-2.html
home-3-hero.webp1600 × 10008:5case-studies/case-study.html, case-studies/index.html, elements.html and 1 more
home-4-hero.webp1920 × 108016:9case-studies/case-study.html, case-studies/index.html, home-4.html
insight-1.webp900 × 6003:2404.html, about-2.html, about-3.html and 59 more
insight-2.webp900 × 6003:2blog/grid-3-columns.html, blog/grid-4-columns.html, blog/grid-sidebar.html and 20 more
insight-3.webp900 × 6003:2blog/grid-3-columns.html, blog/grid-4-columns.html, blog/grid-sidebar.html and 20 more
insight-4.webp900 × 6003:2blog/grid-3-columns.html, blog/grid-4-columns.html, blog/grid-sidebar.html and 12 more
insight-5.webp900 × 6003:2about-2.html, blog/grid-3-columns.html, blog/grid-4-columns.html and 18 more
insight-6.webp900 × 6003:2blog/grid-3-columns.html, blog/grid-4-columns.html, blog/grid-sidebar.html and 10 more
job-banner.webp1920 × 7208:3coming-soon.html, employers/employer.html, jobs/job-banner.html
leader-1.webp600 × 7504:5about-2.html, about-3.html, about.html and 1 more
leader-2.webp600 × 7504:5about-2.html, about.html, elements.html
leader-3.webp600 × 7504:5about-2.html, about.html
leader-4.webp600 × 7504:5about-2.html, about.html
sector-construction.webp800 × 6004:3home-4.html, index.html, sectors/index.html
sector-healthcare.webp800 × 6004:3about-2.html, elements.html, home-4.html and 2 more
sector-hospitality.webp800 × 6004:3about-2.html, home-4.html, index.html and 1 more
sector-logistics.webp800 × 6004:3about-2.html, elements.html, hire-talent/service.html and 5 more
sector-office.webp800 × 6004:3elements.html, home-3.html, home-4.html and 2 more
sector-tech.webp800 × 6004:3home-3.html, home-4.html, index.html and 1 more
temp-work.webp900 × 11254:5blog/grid-3-columns.html, blog/grid-4-columns.html, blog/index.html and 5 more

Replacing images

  • Keep the file name, or change the src in the pages that use it. Keep the shape: the layouts crop with object-fit, but a photo of the same ratio needs no cropping.
  • Every <img> has width and height, so the page doesn't jump as images load. If your image has another size, update them to its real size (the ratio is what counts).
  • WebP at a quality of about 80 keeps pages light; JPEG and PNG work too.
  • The two hero people (hero-person.webp, home-2-person.webp) are transparent cut-outs standing on a shape: use a PNG or WebP with a transparent background, framed like the placeholder.
  • Photos that only illustrate a card or a section have an empty alt, as the text beside them says what they show. Give an image that carries information of its own a short description in alt.
  • Images lower down the page carry loading="lazy", so they load as the visitor scrolls to them.

The preview's photos

The live preview uses free stock photos, 27 under CC0 1.0 and 11 under Unsplash License. They aren't in the download. If you use photos like them, check each one's licence and model releases for your use.

Accessibility

Accessibility is built in, aiming at WCAG 2.2 level AA: every page passes axe-core's automated checks in both themes, and the keyboard reaches everything. What the template does:

  • A skip link, landmarks (header, navigation, main, footer) and one <h1> per page, with headings in order.
  • Every control has a label, and every icon-only link or button a name. Decorative icons and images are hidden from screen readers.
  • A visible focus ring on everything that takes the keyboard focus, in both themes and every colour scheme.
  • Menus, modals, the offcanvas, tabs, the accordion and the sliders work from the keyboard; Esc closes menus and windows.
  • Text meets WCAG AA contrast (4.5:1, or 3:1 for large text) in both themes and all colour schemes.
  • Motion respects the reduced-motion setting, the video has captions, and the countdown leaves its date in words for screen readers.
  • Charts come with a table of their numbers.

When you change the pages, keep these up: write alt text for images that carry information, label new fields, give icon-only links an aria-label, keep headings in order, and check new colours for contrast. Automated checks find only part of what matters, so try your finished pages with the keyboard alone and with a screen reader.

SEO and performance

SEO

  • Every page has its own <title>, a meta description, one <h1> and headings in order. The layout variants of one design (the blog archives, the post layouts, two of the job page layouts) share a description. Rewrite them for your business, giving each page you keep a description of its own.
  • There is no structured data, Open Graph or sitemap.xml in the template, since they depend on your content and domain. A recruitment site gains most from JobPosting structured data on its job pages, which can show jobs in Google's job search.
  • sitemap.html is a sitemap for people. Generate an XML sitemap for search engines on your server or from your CMS.

Performance

  • No build step, and only the libraries each page needs: MapLibre only where there is a map.
  • Images are WebP with their sizes set; those lower down load lazily, and maps start only as they come near the screen.
  • Fonts are two variable files, with font-display: swap.
  • On your server: compress responses (gzip or Brotli), cache assets/ for long, and, if you like, minify style.css and functions.js and preload the fonts (see Fonts and type).

Browser support

The template uses current CSS: :has() for its CSS-only switches and toggles, light-dark() for the dark theme and color-mix() for tints and shadows, together with logical properties, scroll snap and IntersectionObserver.

The browser versions these features need
FeatureChrome and EdgeFirefoxSafari
:has()10512115.4
light-dark()12312017.5
color-mix()11111316.2
  • Browsers without light-dark() get the light theme with every colour in place, and the theme switch hides itself.
  • The maps need WebGL; without it, or offline, the list of places shows instead.
  • Internet Explorer is not supported.

Removing the demo parts

The live preview carries two menus that are not part of the theme: Layouts, which jumps between the page variants, and Colours, which previews the colour schemes. Remove them for your site:

What to remove
PartRemove
Layouts menuOn every page, the block from <!-- Demo Layout Switcher to its <!-- .demo-switch end -->. In style.css, the Demo Layout Switcher rules (section 29).
Colours menuOn every page, the block from <!-- Demo Colour Switcher to its <!-- .demo-switch end -->. The Demo Colour Scheme part of theme.js, the Colour Switcher section of functions.js, and the Demo Colour Switcher rules in style.css (section 29).
Both menus goneThe Demo Menus section of functions.js, and the .demo-switch ~ .back-to-top rule in style.css (section 38), which lifts the back-to-top button above the demo buttons.
Prototype noteThe .prototype-note paragraph in thank-you.html, once the forms send data.
Sample dataThe JSON in #dash-data and #portal-data, once your back end prints its own.

elements.html, typography.html and sitemap.html are reference pages: keep them for your team, or remove them and their links from the menus, the footer and the sitemap. The Pages menu links to every design for the demo; trim it to the pages your site has.

Moving to a CMS

The pages are made to become a CMS theme. Each design is one page, and the shared parts are blocks of their own, so they map onto templates and partials.

From pages to templates
PagesIn a CMS
Header, mobile menu, footer, cookie banner, modalsPartials, or the theme's header and footer templates; the menus come from the CMS's menu settings, which also mark the current item
jobs/index.html, jobs/list.html, jobs/map.htmlThe job archive (one view, or a setting), with real search, filters and pagination
jobs/job.html and its two other layoutsThe single job template; the layout becomes a setting
sectors/, locations/, team/, employers/, case-studies/, hire-talent/service.htmlArchive and single templates for sectors, branches, consultants, employers, case studies and services
blog/The post archive (pick a layout), the single post and the comments
about*.html, contact*.html, legal.html and the other pagesPage templates or block patterns
account/, dashboard/Signed-in areas for job seekers and for staff, fed from your applications, rota and payroll data
FormsForm handlers with server-side validation, consent records and file storage for CVs

What only looks real until a back end takes over: job search, filters, sorting and pagination; branch search by postcode; carrying a search across the grid, list and map views; the Open now label on Home 5; sign in, accounts and saved jobs per account; job alerts; and every form.

Troubleshooting

  • A page shows without its styles. It was opened from inside the ZIP, or moved away from assets/. Unzip the whole download and keep the folders together; pages in sub-folders reach the shared files with ../.
  • A map shows a list of places instead of the map. The map needs an internet connection, WebGL and access to openfreemap.org; an ad blocker or a strict Content Security Policy can stop it. A page also needs MapLibre's script before functions.js (see Anatomy of a page).
  • The theme, the saved jobs or the cookie choice aren't remembered. The browser is blocking storage (some private windows and strict settings do), or the site's data was cleared. Everything still works on the page itself.
  • The dashboard or the portal shows the sample again. Their changes live in the browser: another browser, a private window or cleared site data starts from the sample, and the Restore buttons bring it back on purpose.
  • A form opens the thank-you page, but nothing arrives. The forms aren't connected yet (see Forms).
  • The header's links wrap onto two lines. An item was added or a label lengthened. Check the header from 992 to 1280px; shorten the labels, or move an item into a menu.
  • Headings show in Arial or another system font. The font files moved, or the @font-face paths changed: they are relative to style.css.

Sources and credits

The template is built with these, each under its own licence, kept beside its files and listed in assets/CREDITS.md:

Libraries, fonts and data
NameVersionLicenceIn the templateWebsite
Bootstrap5.3.8MITassets/vendor/bootstrapgetbootstrap.com
jQuery4.0.0MITassets/vendor/jqueryjquery.com
Font Awesome Free7.3.1Icons CC BY 4.0, fonts SIL OFL 1.1, code MITassets/vendor/fontawesomefontawesome.com
MapLibre GL JS5.24.0BSD 3-Clauseassets/vendor/maplibremaplibre.org
Red Hat Display and Red Hat TextSIL Open Font License 1.1assets/fontsGitHub
Map tilesMap data © OpenStreetMap contributors (ODbL), tiles from OpenMapTilesLoaded from OpenFreeMapopenfreemap.org
  • The photos in the live preview are free stock photos (Unsplash License and CC0) and aren't included; the download has placeholders in their place (see Images).
  • The video in the preview was made for the template from CC0 photographs; the download has a placeholder video.
  • The people, companies, figures, jobs and reviews are made up, and the client names are fictional.

Changelog

Version 1.0.0
Initial release.

When an update comes out, this list says what changed. Keep your own styles and scripts in files of your own (see CSS and JavaScript), and an update is mostly a matter of replacing style.css, assets/js/ and the pages you haven't changed, then comparing the ones you have.

Support

If something doesn't work as this guide describes, contact us through the Support tab of the item's page on ThemeForest. Tell us the page, the browser and what you expected to happen, and we'll get back to you.

Item support covers questions about how the template works, problems and bugs in it, and help with the libraries it includes. It doesn't cover customisation, installation or connecting the template to a back end, which are services of their own.