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
- Unzip the download. The template folder holds the pages,
style.cssandassets/;documentation/holds this guide. - Open
index.htmlin your browser. Every page works straight from your disk; only the maps need an internet connection, for their tiles. - Edit the pages in any code editor. There is no build step: save the file and reload the page.
- 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/:
python3 -m http.server 8000Editing 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:
<!-- 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:
├── 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 fromstyle.cssinstead (see CSS). assets/CREDITS.mdand the licence files inassets/fontsandassets/vendormust 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.
- Replace the images in
assets/imgand the video inassets/video: the download has placeholders that show the size each slot expects (see Images). - 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).
- Connect the forms to your back end, and remove the prototype note from
thank-you.html(see Forms). - Pick your colour scheme and remove the demo's Layouts and Colours menus (see Colour schemes and Removing the demo parts).
- 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. - Load your analytics or marketing scripts only with the visitor's consent (see Cookie consent), and have
legal.htmlwritten for your business. If you keep the maps, say in your privacy notice that the map tiles come from OpenFreeMap (see Maps). - Connect the candidate portal and the agency dashboard to your data, or remove them (see Agency dashboard and Candidate portal).
- Set the browser bar colour (
<meta name="theme-color">) and the favicon. - 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)
| Page | What it shows |
|---|---|
Home 1 — Staffing agencyindex.html | Home 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.html | Home 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.html | Home 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.html | Home 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.html | Home 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)
| Page | What it shows |
|---|---|
Job gridjobs/ | Search 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/ | Search results as dense rows, with an inline filter bar and a job alert strip.Page Title · Search Results · Closing Conversion |
Job mapjobs/ | Jobs 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.html | A 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/ | The 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/ | The 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/ | The 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.html | Registration with a CV: details, the work wanted and a file upload.Page Title · Registration Form |
Hire talent (8)
| Page | What it shows |
|---|---|
Hire talenthire-talent/ | Services 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/ | The 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.html | A staff request form in three parts, beside what happens next.Page Title · Request Form |
Employer profileemployers/ | The 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/ | Every case study, with figures, under a photo page title.Page Title · Key Figures · All Case Studies · Closing Conversion |
Case studycase-studies/ | The 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/ | The six sectors as cards, and why specialist teams matter.Page Title · All Sectors · Why Specialists · Closing Conversion |
Sector pagesectors/ | The 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)
| Page | What it shows |
|---|---|
About 1 — Storyabout.html | About 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.html | About 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.html | About 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/ | The 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.html | Careers at the agency: life there, what staff say and open roles.Page Title · Life at PeopleForward · In Their Words · Open Roles · Closing Conversion |
Sustainabilitysustainability.html | Impact in numbers, three commitments and targets.Page Title · Impact in Numbers · Three Commitments · Targets · Closing Conversion |
Contact 1 — Form and mapcontact.html | Contact 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.html | Contact 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.html | Contact 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/ | All branches as cards beside a map whose pins open the branch page.Page Title · All Branches · Closing Conversion |
Branch pagelocations/ | The 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)
| Page | What it shows |
|---|---|
Overviewaccount/ | The 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/ | Every application with its stages, next step and history; status filters and Withdraw.Page Title · Application List |
Saved jobsaccount/ | The jobs bookmarked anywhere on the site, as tickets.Page Title · Saved Jobs |
Job alertsaccount/ | Job alerts to create, pause, edit and delete.Page Title · Alerts |
Shiftsaccount/ | Shift offers to take or turn down, the booked shifts with directions, and when the worker can work. |
Timesheets and payaccount/ | This week's timesheet with live totals, payslips, the tax year so far and holiday requests.Page Title · Pay Figures · Timesheet and Holiday |
Documentsaccount/ | The checks the agency needs, the worker's files with an upload form, and papers from the agency. |
Settingsaccount/ | Personal 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)
| Page | What it shows |
|---|---|
Overviewdashboard/ | The 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/ | The 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/ | The 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/ | The 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/ | The signed-in consultant's profile: figures, targets, candidates, vacancies and contact details.Page Title · Profile Header · Key Figures · Work and Details |
Edit profiledashboard/ | Edit profile: details, introduction, specialisms, a new photo and where they are today; saved changes show across the dashboard.Page Title · Profile Form |
Blog (19)
| Page | What it shows |
|---|---|
Blog homeblog/ | The blog home: category tabs, a featured post, a grid of posts and the newsletter.Page Title · Articles · Newsletter · Closing Conversion |
Large image, right sidebarblog/ | Posts with large images, sidebar on the right.Page Title · Posts · Closing Conversion |
Large image, left sidebarblog/ | Posts with large images, sidebar on the left.Page Title · Posts · Closing Conversion |
Large image, no sidebarblog/ | Posts with large images in one centred column.Page Title · Posts · Closing Conversion |
Medium image, right sidebarblog/ | Posts with the image beside the text, sidebar on the right.Page Title · Posts · Closing Conversion |
Medium image, left sidebarblog/ | Posts with the image beside the text, sidebar on the left.Page Title · Posts · Closing Conversion |
Medium image, no sidebarblog/ | Posts with the image beside the text, without a sidebar.Page Title · Posts · Closing Conversion |
Grid, two columns and a sidebarblog/ | A grid of post cards in two columns beside the sidebar.Page Title · Posts · Closing Conversion |
Grid, three columnsblog/ | A grid of post cards in three columns.Page Title · Posts · Closing Conversion |
Grid, four columnsblog/ | A grid of post cards in four columns.Page Title · Posts · Closing Conversion |
Masonry, two columns and a sidebarblog/ | Masonry in two columns beside the sidebar, with pull quotes among the posts.Page Title · Posts · Closing Conversion |
Masonry, three columnsblog/ | Masonry in three columns, with pull quotes among the posts.Page Title · Posts · Closing Conversion |
Masonry, four columnsblog/ | Masonry in four columns, with pull quotes among the posts.Page Title · Posts · Closing Conversion |
Timeline, full widthblog/ | The posts on a two-sided timeline, by month.Page Title · Posts · Closing Conversion |
Timeline, with a sidebarblog/ | The posts on a one-sided timeline beside the sidebar.Page Title · Posts · Closing Conversion |
Post, right sidebarblog/ | The 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/ | The post with its sidebar on the left.Article Header · Article · Related Advice · Closing Conversion |
Post, no sidebarblog/ | The post without a sidebar.Article Header · Article · Related Advice · Closing Conversion |
Post, full-width photoblog/ | The post with its photo full width behind the title.Article Header · Article · Related Advice · Closing Conversion |
Help, account and the rest (13)
| Page | What it shows |
|---|---|
Temporary worktemporary-work.html | Temporary 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.html | Answers 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.html | Sign in. Its notes for #reset-sent, #account-created and #account-deleted show when the address ends with them. |
Create an accountregister.html | Create an account as a job seeker or an employer (Bootstrap pills switch the two forms). |
Reset your passwordforgot-password.html | Reset a password; the form comes back to login.html#reset-sent. |
Coming sooncoming-soon.html | A countdown to the launch date and a notify form, without header or footer. |
Maintenancemaintenance.html | Progress and what still works during maintenance, without header or footer. |
Page not found404.html | Page not found, with a job search and links onwards. |
Form confirmationthank-you.html | The confirmation the site's forms open. Remove its prototype note once your forms send data. |
Legal and policieslegal.html | The privacy notice, cookie policy, terms, accessibility statement and modern slavery statement, each a section of one page.Page Title · Legal Text |
Sitemapsitemap.html | Every page, grouped.Page Title · All Pages |
Elementselements.html | The style guide: every component in numbered groups, each with the classes that build it. |
Typographytypography.html | The 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.
| Item | Page | Sample |
|---|---|---|
| Job | jobs/ | Warehouse Operative |
| Sector | sectors/ | Logistics & Warehousing |
| Branch | locations/ | PeopleForward Leeds |
| Service | hire-talent/ | Temporary staffing |
| Case study | case-studies/ | 210 pickers in 19 days for peak |
| Employer | employers/ | Northgate Logistics |
| Consultant | team/ | Chloe Hartley |
| Blog post | blog/ | Seven interview questions you will almost certainly be asked — and how to answer them |
| Candidate (dashboard) | dashboard/ | Tomasz Nowak |
| Consultant (dashboard) | dashboard/ | Chloe 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.htmland theblog/post-*.htmlpages). 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,#termsand#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
<!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.jssits 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
| Block | What it is |
|---|---|
| Skip link | The first tab stop; it jumps past the header to <main id="main">. |
| Announcement Bar | A short message with a link, above the header (.announce). |
| Header | The logo, the menus (.site-nav), the theme switch, Sign in, Upload CV, the main call to action and the menu button. |
| Mobile Menu | The menu below 992px: a Bootstrap offcanvas (). |
| Content | The page itself: <main id="main">, one block after another. |
| Footer | One of the nine footers. |
| Cookie Consent | The cookie banner, hidden until the script shows it. |
| Modals | Sign in and cookie settings on every page, then the page's own (the video, quick apply, the newsletter). |
| Demo Colour Switcher | Demo only: the Colours menu. |
| Demo Layout Switcher | Demo only: the Layouts menu. |
| Toast and Back to Top | The one toast every message uses, and the back-to-top button. |
| JavaScripts | jQuery, Bootstrap's bundle and functions.js (and MapLibre on pages with a map). |
Scripts
<!-- 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:
<!-- 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/andaccount/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.htmlandmaintenance.htmlhave 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.
<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--lighton dark footers), the dashboard sidebar and top bar, and the launch pages. Change the name everywhere with a search across files forPeople<span>Forward</span>. - The
<span>inside.brand__nametakes 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-labelwith your company's name:
<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>.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
| Detail | Sample | Where |
|---|---|---|
| Company name | PeopleForward, PeopleForward Recruitment Ltd | Every page: the logo, the titles and the copyright line |
| Phone numbers | 0113 496 0123 and others, as tel:+441134960123 in the links | The mobile menu, the footer, contact cards and branches. They come from the ranges Ofcom keeps for drama, so they ring nowhere. |
| E-mail addresses | hello@envato.com and other addresses at envato.com | The footer, contact pages, profiles and the sample data |
| Head office | 3 Park Square East, Leeds LS1 2NE | The footer, the contact pages and the branch page |
| Company line | Registered in England No. 09876543 | The bottom bar of the footers |
| Social links | The home pages of LinkedIn, Facebook and Instagram | The 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.
| Scheme | File | Primary | Accent |
|---|---|---|---|
| Blue (default) | assets/ | #1f4be0 | #ff6b4a |
| Violet | assets/ | #6a35d9 | #f571a4 |
| Crimson | assets/ | #b20d43 | #f8bd40 |
| Orange | assets/ | #a13b00 | #55c6f4 |
| Green | assets/ | #006a3a | #b5ed60 |
| Teal | assets/ | #006565 | #ffb346 |
Choosing a scheme
Every page links one scheme, right after style.css:
<link rel="stylesheet" href="assets/css/colors/blue.css" id="color-scheme">- Search all pages for
colors/blue.cssand replace it with the file you want, such ascolors/teal.css. - 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
- Copy
blue.cssto a new file inassets/css/colors/, for examplebrand.css. - Change the values.
--c-primary-fillcarries white text,--c-primaryis the text and link colour (lighter in the dark theme),--c-accentcarries navy text, and--bs-primary-rgbis the primary fill as three numbers, for Bootstrap's utilities. - Keep text readable: at least 4.5:1 for white on
--c-primary-fill, navy (#0c1838) on--c-accent,--c-primaryon 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. - Repeat the light values in the file's
@supports notblock, for browsers withoutlight-dark(). - Point the pages'
#color-schemelink 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(), andcolor-schemepicks 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.jsremembers the choice inlocalStorage(pf-theme), andtheme.jsputs it back asdata-themeon<html>before anything is painted, together with Bootstrap'sdata-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.
<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 lang="en" data-theme="dark" data-bs-theme="dark">One theme only
- Remove the
.theme-switchfieldset from the header of every page, and from the top bar of the dashboard and portal pages. - Put
data-theme="light" data-bs-theme="light"(ordark) on<html>, and set<meta name="color-scheme">to the same word. - Delete the Light / Dark part of
theme.jsand the Theme Memory section offunctions.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:
.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.
@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;
}| Token | Value |
|---|---|
--font-display | "Red Hat Display", "Segoe UI", Roboto, Arial, sans-serif |
--font-text | "Red Hat Text", "Segoe UI", Roboto, Arial, sans-serif |
--fs-display | clamp(2.75rem, 1.5rem + 4vw, 4.75rem) |
--fs-h2 | clamp(2rem, 1.45rem + 2.2vw, 3.375rem) |
--fs-h3 | clamp(1.375rem, 1.2rem + 0.6vw, 1.75rem) |
--fs-lead | clamp(1.0625rem, 1rem + 0.35vw, 1.25rem) |
--fs-body | 1.0625rem |
--fs-sm | 0.9375rem |
--fs-xs | 0.8125rem |
Changing the fonts
- Put your font files in
assets/fonts(WOFF2), with their licence. - Point the two
@font-facerules at the top ofstyle.cssat them, with their family names and weight ranges. - Set
--font-displayand--font-textto 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.htmlshows 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.
<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>iconsets the glyph in a square box (1.25rem) so icons line up with text;icon--smmakes it 1rem.fa-solid,fa-regularandfa-brandspick the style. Any icon of the free set works: search the gallery at fontawesome.com and copy itsfa-…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.htmlshows the theme's interface icons. - Select menus sit in a
.selectwrapper 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.
| Token | Light | Dark | Used for |
|---|---|---|---|
--c-white | #ffffff | #10182b | Page and card background |
--c-surface | #f4f6fb | #0b1222 | Grey section background |
--c-tint | #e9efff | #1a2650 | Pale primary behind chips and selected items; the map's land |
--c-tint-fill | #e9efff | Same | The pale tint in both themes, for hovers on white buttons |
--c-primary | #1f4be0 | #8eaaff | Primary colour of text and links |
--c-primary-fill | #1f4be0 | Same | Primary fills that carry white text: buttons, bands, the hero stage |
--c-primary-hover | #173bbd | Same | Hover of the primary fills |
--c-navy | #0c1838 | #eef2fb | Headings |
--c-deep | #0c1838 | #141f42 | Navy panels, and the text on accent fills |
--c-navy-2 | #18264f | #1f2c57 | A second navy, for hovers and panels on navy |
--c-text | #17213d | #dde3f0 | Body text |
--c-text-2 | #4a5470 | #aeb8cf | Secondary text |
--c-text-3 | #626b88 | #8e98b2 | Muted text: captions, dates, map labels |
--c-line | #e1e6f0 | #263254 | Hairlines and card borders |
--c-line-strong | #c8d0e2 | #36446c | Field borders and stronger dividers |
--c-accent | #ff6b4a | Same | Accent fills: urgent badges, strokes, calls to action |
--c-accent-hover | #ff5a35 | Same | Hover of the accent fills |
--c-accent-soft | #ffe8e1 | #3b211d | Background of accent badges |
--c-accent-ink | #b8341b | #ff9e88 | Text of accent badges; accent-coloured text |
--c-accent-light | #ffb8a6 | Same | Accent text and icons on navy; on the primary fill (about 4:1), large text and icons only |
--c-mint-soft | #dcf5ea | #11362a | Background of success badges and states |
--c-mint-ink | #12704b | #74dfb1 | Text of success badges and states |
--c-sun-soft | #fff1d1 | #3b2e0e | Background of warning badges and highlighted text |
--c-sun-ink | #8a5a00 | #f4c766 | Text of warning badges and states |
--c-map-edge | #9fb3f5 | #3b4f8f | Map borders and road casings |
--c-glow | rgb(255 232 225 / 0.7) | rgb(255 107 74 / 0.1) | Accent glow in the hero background |
--c-glow-soft | rgb(255 232 225 / 0.55) | rgb(255 107 74 / 0.08) | Softer glow behind page titles |
--c-on-color | #ffffff | Same | Text on coloured fills |
--c-on-dark-2 | rgb(255 255 255 / 0.78) | Same | Secondary text on navy and on the primary fill |
| Token | Value |
|---|---|
--space-xs | 0.75rem |
--space-s | 1rem |
--space-m | 1.5rem |
--space-l | 2rem |
--space-xl | 3rem |
--space-2xl | clamp(3rem, 2rem + 3vw, 5rem) |
--space-section | clamp(4.5rem, 3.25rem + 5vw, 8rem) |
--gutter | clamp(1.25rem, 0.6rem + 2.6vw, 3rem) |
--grid-gap | clamp(1rem, 0.6rem + 1.2vw, 1.75rem) |
--container | 82rem |
--header-h | 4.75rem |
| Token | Value |
|---|---|
--radius-s | 0.625rem |
--radius-m | 0.875rem |
--radius-l | 1.25rem |
--radius-xl | 1.75rem |
--shadow-card | 0 1.5rem 3rem -1.25rem light-dark(rgb(12 24 56 / |
--shadow-float | 0 1.25rem 2.5rem -0.75rem light-dark(rgb(12 24 56 / |
| Token | Value |
|---|---|
--ease-out | cubic-bezier(0.22, 1, 0.36, 1) |
--dur-fast | 160ms |
--dur-base | 300ms |
--dur-slow | 700ms |
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:
<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>| Class | What it does |
|---|---|
section | A block with the standard vertical spacing |
section--surface | Grey background (--c-surface) |
section--tight | Less vertical spacing |
section-head | Kicker, heading and lead text over a block's content |
section-head--center | Centres the section head |
section-head--action | Puts a link or button beside the heading, on the right |
kicker | The small line over a heading |
t-h1, t-h2 | Heading 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
| Width | Bootstrap name | What changes |
|---|---|---|
| 576px | sm | Two-column card grids; the header shows its call to action |
| 768px | md | Wider grids and split sections |
| 992px | lg | The header shows its menus (the mobile menu below this); sidebars sit beside the content |
| 1200px | xl | Sign 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-100and the rest. - The
revealclass on many cards marks them for a scroll-in animation of your own; the template doesn't animate them.
Header and menus
The header is a Bootstrap navbar with the theme's own menus. Below 992px it gives way to the mobile menu.
A menu
Each item is a link to its main page and a chevron button that opens the menu from the keyboard:
<li class="nav-item dropdown">
<a class="nav-link" href="index.html">Home</a>
<button class="nav-toggle" type="button" data-bs-toggle="dropdown" data-bs-display="static" aria-expanded="false"><i class="icon icon--sm fa-solid fa-chevron-down" aria-hidden="true"></i><span class="visually-hidden">Home menu</span></button>
<div class="dropdown-menu nav__menu">
<ul class="nav__panel nav__panel--single">
<li><a class="dropdown-item" href="index.html"><i class="icon fa-solid fa-house" aria-hidden="true"></i><span><strong>Home 1 — Staffing agency</strong><span>Find a job or hire talent</span></span></a></li>
<li><a class="dropdown-item" href="home-2.html"><i class="icon fa-solid fa-magnifying-glass" aria-hidden="true"></i><span><strong>Home 2 — Job board</strong><span>Search first, jobs as tickets</span></span></a></li>
<li><a class="dropdown-item" href="home-3.html"><i class="icon fa-regular fa-building" aria-hidden="true"></i><span><strong>Home 3 — For employers</strong><span>A staff request up front</span></span></a></li>
<li><a class="dropdown-item" href="home-4.html"><i class="icon fa-regular fa-image" aria-hidden="true"></i><span><strong>Home 4 — Photo-led</strong><span>A photo under a clear header</span></span></a></li>
<li><a class="dropdown-item" href="home-5.html"><i class="icon fa-solid fa-location-dot" aria-hidden="true"></i><span><strong>Home 5 — Local branch</strong><span>One branch as the home page</span></span></a></li>
</ul>
</div>
</li>- A menu shows on hover and while its link has the keyboard focus. The chevron is Bootstrap's dropdown: Enter, Space or ↓ open it, the arrow keys move through it and Esc closes it.
nav__panellists items with an icon and a line of text (nav__panel--singlefor a one-column list). The Pages and Blog menus are full-width panels:nav__menu--megaholding a.megaof.mega__colcolumns and a.mega__promocard.- The item whose menu links to the page carries
aria-current="true"on its.nav-link, which marks it as the current section. Move it when you copy the header to another page. - The menus are sized to stay on one line from 992px. If you add an item or lengthen one, check the header at 992, 1200 and 1280px.
Mobile menu
#mobile-menu is a Bootstrap offcanvas opened by the header's menu button. It lists the same sections: each name opens its main page and its chevron opens the rest (Bootstrap's collapse). The main calls to action and the phone number sit at its foot.
Header actions
Beside the menus: the theme switch, Sign in (an icon that opens #login-modal, or login.html without script) and Upload CV from 1200px, the Request staff button from 576px, and the menu button below 992px.
Variants
| Variant | Page | How it works |
|---|---|---|
| Transparent | home-4.html | site-header--transparent lies over the hero photo and turns solid as the page scrolls (.is-scrolled, set by functions.js). It needs the .js class that theme.js puts on <html>; without script the header stays solid. |
| Jobs mega menu | home-2.html | Find a job opens a full-width panel: jobs by type, by sector and by branch, beside a card with the live job count and a Search jobs button. |
Announcement bar
.announce, above the header, holds two versions of its message: Bootstrap's d-none d-md-inline and d-md-none swap the long one for the short one below 768px. Delete the block to drop the bar.
Page titles
Inner pages open with a .page-hero: a breadcrumb, the <h1>, a lead and, in some variants, an image or a search.
<!-- 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 -->| Class | Look | For example |
|---|---|---|
page-hero--compact | Title, breadcrumb and lead, no image | blog/, blog/, blog/ |
page-hero--center | Centred title | contact-2.html, elements.html, salary-guide.html |
page-hero--image | The title over a photo | about-3.html, case-studies/, case-studies/ |
page-hero--media | Title beside a photo | about.html, faq.html, hire-talent/ |
page-hero--search | Title with the job search (job listings) | jobs/, jobs/ |
page-hero--job | The job page's header | jobs/ |
page-hero--branch | The branch page's header, with its map | locations/ |
page-hero--map | The jobs map's title | jobs/ |
page-hero--person | A portrait beside the title (consultant profile) | team/ |
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.
| Group | Part | What it shows | Anchor |
|---|---|---|---|
| 01. Colours | Basics | Every 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 |
| 02. Icons | Basics | Font 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 |
| 03. Buttons | Basics | Bootstrap’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 |
| 04. Badges and chips | Basics | Small labels for status, categories and filters. | elements.html |
| 05. Navigation | Basics | Ways around a section: where you are, sibling pages and pages of results. | elements.html |
| 06. Feedback | Basics | Messages 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 |
| 07. Headings and lists | Content | The heading that opens each section, and the lists used across the pages. | elements.html |
| 08. Steps and figures | Content | Processes, milestones and numbers, drawn as cards, rows and strips. | elements.html |
| 09. Accordion | Content | FAQs as Bootstrap’s accordion: several answers can be open at once, and the plus turns into a minus. | elements.html |
| 10. Cards | Content | Cards for services, sectors, articles and employers. Most are links: the title link stretches over the whole card. | elements.html |
| 11. People | Content | Portraits stand on a colour block; a consultant without a photo shows initials instead. | elements.html |
| 12. Testimonials | Content | Quotes from candidates and clients, with stars, a tag and an optional photo. | elements.html |
| 13. Jobs | Recruitment | Job cards drawn as shift tickets, compact rows for long lists and a slider that swipes, scrolls or steps with its arrows. | elements.html |
| 14. Search and map | Recruitment | Search bars, the filters sidebar (a collapsible panel on phones) and the branch map, which works for any country. | elements.html |
| 15. Forms | Recruitment | Native validation and Bootstrap’s form controls, selects with the theme’s own menu and search; the choices are Bootstrap’s toggle buttons. | elements.html |
| 16. Modals and video | Overlays | Bootstrap’s modals for signing in, quick apply, the newsletter and cookie settings, the video lightbox and the cookie banner. | elements.html |
| 17. Pricing | Conversion | Pricing cards for fees or plans, with the featured one raised and badged. | elements.html |
| 18. Calls to action | Conversion | Bands that close a page and cards for sidebars. The split call to action at the bottom of this page ends most pages. | elements.html |
| 19. Headers, titles and footers | Layout | The header, page title and footer each come in more than one look, and every page uses one of each. | elements.html |
| 20. Blog | Content | The 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 |
| 21. Extras | Extras | The 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 |
| 22. Dashboard | Dashboard | The 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 |
| 23. Candidate portal | Dashboard | The 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 |
Buttons
<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.
<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
<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:
<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:
<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:
<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.
<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.
<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.
| Forms | Action |
|---|---|
| Contact, request staff, CV upload, comments, job alerts, newsletter, apply | thank-you.html, the confirmation page |
| Job searches | jobs/ |
| Branch and blog searches | locations/ and blog/ |
| Quick staff request (Home 1, Home 3) | request-staff.html, the full form |
| Sign in | account/, the candidate portal |
| Create an account | login.html |
| Reset password | login.html |
| Dashboard and portal forms | Saved in the browser by functions.js (see Data kept in the browser) |
Connecting a form
- Give every field a
name, and every radio button and checkbox avalue(without one, a ticked box sendson). - Set the form's
actionto your form handler (a script on your server, your CMS's form plugin or a form service) andmethod="post". - For a file upload, add
enctype="multipart/form-data". - Check every field again on the server, and protect the form from spam (a hidden honeypot field, or a captcha).
- Remove the prototype note from
thank-you.html, or point the form at your own confirmation page.
<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:
<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:
<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:
<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.
<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>withgeo-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-mapopens it on its one place at street level instead. - On the jobs map, areas are
.geo-map__clusterlinks with the number of jobs as their text. Hovering or focusing a job lights up its area: the job carriesdata-areaand its clusterdata-pinwith the same code, andstyle.csspairs 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:
var mapStyle = "https://tiles.openfreemap.org/styles/positron";
var mapThemeColors = true;| Setting | Where | What it does |
|---|---|---|
mapStyle | functions.js | The MapLibre style of every map: another style's URL, or your own copy of OpenFreeMap |
data-map-style | One .geo-map | A style for that map only |
mapThemeColors | functions.js | false keeps the style's own colours on every map (the recolouring is made for OpenFreeMap's styles) |
data-map-colors="style" | One .geo-map | Keeps the style's own colours on that map |
data-zoom | One .geo-map | Opens the map at that zoom on its place |
The map's own words are in mapText, for translation:
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:
$(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:
https://www.google.com/maps/dir/?api=1&destination=3%20Park%20Square%20East%2C%20Leeds%20LS1%202NE%2C%20United%20KingdomImportant. 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.
<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><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.mp4with your video (MP4, H.264) andpeopleforward-story.vttwith 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.
<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:
<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 offunctions.js. - To add a kind of cookie, add a box with its own
data-consent-type(for examplepreferences) 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.jsmakes 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-extraand#calc-extra-hours; the results are the<output>elements#calc-basic,#calc-holiday,#calc-totaland#calc-year. - Holiday pay is
holidayRatein the Pay Calculator section offunctions.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"inmoney(), and the £ in the field labels and the pre-filled results ofsalary-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:
<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-meshow the signed-in consultant's saved profile: their text, an image'ssrcor a link's address. - The charts are HTML and CSS: each bar's height is a percentage in its
--hand 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:
{
"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"
}
]
}| Key | Type |
|---|---|
today | text |
me | text |
candidatePage | text |
team | object |
candidates | object |
types | object |
priorities | object |
categories | object |
tasks | list |
notes | list |
todayis 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,assigneeanddone; a note hasid,author,at,category,pinned,candidateandtext. - To save to your server, replace the
saveList()calls in the Tasks and Notes sections offunctions.js, and thelocalStorage.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-accountshow the saved name (name,firstorinitials). - 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:
{
"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"
}| Key | Type |
|---|---|
today | text |
week | text |
loginPage | text |
account | object |
saved | list |
alerts | list |
offers | list |
activeApps | list |
labels | object |
pay | object |
holidayLeft | number |
agentFirst | text |
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.
| Key | Storage | Part | What it holds |
|---|---|---|---|
pf-theme | localStorage | Every page | light or dark: the header switch's choice. theme.js puts it back before the page paints. |
pf-color | sessionStorage | Demo only | The colour scheme picked in the Colours menu, for the rest of the visit in that tab. |
pf-consent | localStorage | Every page | The cookie choices, such as {"analytics": true, "marketing": false}. |
pf-saved | localStorage | Every page | The jobs saved with a bookmark, by the names in their data-job. |
pf-tasks | localStorage | Dashboard | The team's tasks, once one has changed. |
pf-notes | localStorage | Dashboard | The notes, once one has changed. |
pf-profile | localStorage | Dashboard | The consultant profile saved on Edit profile, with the photo. |
pf-withdrawn | localStorage | Portal | The ids of withdrawn applications. |
pf-alerts | localStorage | Portal | The job alerts. |
pf-shifts | localStorage | Portal | The answers to shift offers, by offer id. |
pf-availability | localStorage | Portal | The ticked boxes of the availability form. |
pf-timesheet | localStorage | Portal | This week's timesheet rows and whether it was sent. |
pf-holiday | localStorage | Portal | The holiday requests. |
pf-uploads | localStorage | Portal | The name, kind, size and date of each upload (never the file). |
pf-account | localStorage | Portal | The 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.jsandfunctions.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.
| Section | Components |
|---|---|
| 1. Fonts | |
| 2. Tokens | Colour Scheme, Custom Properties, Bootstrap Bridge, Fallback Without light-dark() |
| 3. Base | Reset, Reboot Adjustments, Element Defaults, Focus & Selection, Accessibility Helpers, Icons, Stretched Link |
| 4. Layout | Container & Section, Section Head, Card Grids, Page Layouts |
| 5. Typography | Headings, Kicker |
| 6. Controls | Buttons, Badges |
| 7. Announcement & Header | Announcement Bar, Site Header, Logo, Primary Navigation, Dropdown Panel, Header Actions, Theme Switch, Menu Toggle, Mobile Menu |
| 8. Hero | Hero Layout, Hero Badge, Title & Brush Mark, Find a Job / Hire Talent Switch, Trust Row, Hero Visual, Floating Cards, Doodles |
| 9. Logos | |
| 10. Entry Points | Entry Cards, Check List, Card Actions & Media |
| 11. Services | |
| 12. Sectors | |
| 13. Jobs (Shift Tickets) | Filter Chips, Job Ticket, CV Banner |
| 14. Results | Results Band, Figures, Testimonials, Testimonial Slider |
| 15. Team | Consultant Cards, Branch Links |
| 16. Insights | |
| 17. Closing Conversion | |
| 18. Footer | Footer Grid, Brand & Contact, Link Columns, Job Alerts, Bottom Bar |
| 19. Inner Pages — Shared Structure | Shared Modifiers, Breadcrumb, Page Hero, Page Layouts, Split |
| 20. Shared Content Blocks | Stat 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 Cards | Person, Contact Card, Side Panel, Mini Steps |
| 22. Search, Filters and Listings | Search Bar, Job Type Tabs, Filters Panel, Results Bar, Job List, Job Alert Card, Pagination, Save Button |
| 23. Job Detail | Job Header, Job Sections, Apply Card, Key Facts, Apply Form Panel |
| 24. Forms | Form Layout, Form Card, Form Grid & Fields, Inputs & Selects, Select Menu, Choice Chips, File Upload, Consent, Submit Row |
| 25. Map and Branches | Map Card, Map, Branch Cards |
| 26. Advice and Articles | Featured Post, Archive Grid, Newsletter Band, Article Header, Article Image, Prose, Tip Box, Pull Quote, Author Box, Sidebar Call to Action, Share Links |
| 27. Company Pages | Weekly Pay Card, Timeline, Job Openings, Table of Contents |
| 28. Confirmation and Error States | State Message, Next Links, Sitemap |
| 29. Layout Variants — Shared Pieces | View Switch, Select in a Search Field, Job Rows, Scroller, Quote Grid, Call Band, Demo Layout Switcher, Demo Colour Switcher |
| 30. Home 2 — Job Board | Board Hero, Shift Pass, Hero Figures, Sector Tiles, Companies Hiring, App Promo, Phone Mockup |
| 31. Home 3 — Employers | Employer Hero, Figures Band, Service Rows, Sector Team Chips, Case Study Cards |
| 32. Home 4 — Photo-Led | Photo Hero, Overlapping Search, Large Figures, Sector Mosaic, Quote Split, Sector List, Accent Call Band |
| 33. Home 5 — Local Branches | Local Hero, Branch Address Card, Rating & Reviews |
| 34. About 2 | Collage Hero, Mission Statement, Numbers, Promises, Team Cards, Branch Map Strip, Accreditations Grid |
| 35. Jobs — List and Map Views | Filter Bar, Job Alert Strip, Map View, Area Groups, Mini Job Card, Map Clusters |
| 36. Job Detail — Banner and Summary Layouts | Job 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 Pages | FAQ Topics, Style Guide Index, Style Guide Sections, Colour Swatches, Icon Tiles, Typefaces, Type Scale, Text Colours and Inline Text, Tables |
| 38. Overlays and Feedback | Modals, Video Lightbox, Toasts, Tooltips, Alerts, Progress Bars, Cookie Banner, Back to Top |
| 39. Header, Footer and Title Variants | Transparent 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 Pages | Pricing Cards, Account Pages, Employer Profile, Consultant Profile, Case Studies, Salary Guide, Coming Soon and Maintenance, Style Guide Additions |
| 41. Blog | Archive Layout, Post Meta, Large and Medium Image Posts, Post Cards, Masonry, Timeline, Sidebar Widgets, Single Post, Comments |
| 42. About and Contact Variants | Audience Cards, Impact, Founder Letter, Awards, Departments, Contact Split |
| 43. Agency Dashboard | Dashboard 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 Portal | Portal Figures, Applications, Shifts, Availability, Timesheet, Payslips, Holiday, Job Alerts, Documents, Settings |
| 45. Motion | Keyframes, 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:
.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:
<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.cssswitches 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.jsfor 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:
| Section | What it does and what it looks for |
|---|---|
| Theme Memory | Stores 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 Switcher | Demo only. Swaps the file name in <link id="color-scheme"> and keeps the scheme for the visit. Hooks: input[name="color"]. |
| Scroller Controls | Adds 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. |
| Tooltips | Starts Bootstrap's tooltips, without fades. Hooks: [data-bs-toggle="tooltip"] with data-bs-title. |
| Toasts | Shows the page's toast () with a message: when a job is saved or removed, and for any button with data-toast="Your message". |
| Select Menus | Opens 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 Consent | Shows .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 Lightbox | Plays the video in when the modal opens and rewinds it when it closes. |
| Transparent Header | Adds .is-scrolled to .site-header--transparent once the page scrolls (Home 4). |
| Back to Top | Shows .back-to-top after a screen of scrolling; it goes up and gives the keyboard focus to the skip link. |
| Pay Calculator | Works out the salary guide's totals as the fields change (.calc__form, the fields and outputs). Holiday pay is holidayRate (0.1207); money() formats the amounts. |
| Countdown | Counts down to the date in data-countdown (ISO 8601) into its [data-unit] numbers, and stays hidden once that date has passed. |
| Dashboard Menu | Names the dashboard and portal sidebar (, data-menu-label) while it opens as a panel below 992px. |
| Dashboard Data | Reads the JSON in and holds the helpers the dashboard shares: lists kept in localStorage, new ids, dates relative to the data's today. |
| Profile | Shows the saved consultant profile in every [data-me] element and runs Edit profile (, the photo preview data-preview, [data-profile-reset]). |
| Tasks | Draws, filters, adds, edits (), 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. |
| Notes | The same for notes in each [data-note-view]: forms with data-note-add, the edit window , pinned notes first. |
| Candidate Filters | Narrows the candidates table with the status buttons ([data-status-filter]), and , through each row's data-status, data-search and data-sector. |
| Saved Jobs | Keeps the jobs saved with a bookmark (.save input[data-job]) and shows only the saved cards ([data-saved-item]) in a [data-saved-list]. |
| Applications | Filters the applications by status ([data-app-filter]) and withdraws one after asking (). |
| Job Alerts | Creates, pauses, edits () and deletes job alerts. |
| Shifts | Takes or turns down shift offers ([data-shift-take], [data-shift-decline]) and keeps the availability form (). |
| Timesheet | Works out hours, overtime, pay and holiday as the timesheet () is filled in; Save draft, Send for approval and Change it; opens each payslip in . |
| Holiday | Adds a holiday request from , takes its hours off what's left, and cancels a request while it waits. |
| Documents | Lists an uploaded file with its name, kind and size (). The file itself stays on the visitor's computer: a real site sends it to its server here. |
| Account | Saves the settings form (), shows the name in every [data-account] element, downloads the account's data as JSON and deletes the account. |
| Maps | Turns 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 Menus | Demo 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.
| File | Size (px) | Shape | Pages |
|---|---|---|---|
about-office.webp | 900 × 1125 | 4:5 | about-2.html, about.html, forgot-password.html and 2 more |
about-team.webp | 1200 × 800 | 3:2 | about-2.html, about.html, case-studies/ and 1 more |
avatar-1.webp | 240 × 240 | 1:1 | case-studies/, elements.html, hire-talent/ and 4 more |
avatar-2.webp | 240 × 240 | 1:1 | blog/, blog/, blog/ and 5 more |
avatar-3.webp | 240 × 240 | 1:1 | index.html |
avatar-4.webp | 240 × 240 | 1:1 | index.html |
avatar-5.webp | 240 × 240 | 1:1 | blog/, blog/, blog/ and 3 more |
avatar-6.webp | 240 × 240 | 1:1 | index.html |
careers-1.webp | 900 × 600 | 3:2 | about-2.html, about-3.html, case-studies/ and 4 more |
careers-2.webp | 900 × 600 | 3:2 | about-2.html, blog/, blog/ and 6 more |
consultant-1.webp | 600 × 750 | 4:5 | about-2.html, account/, account/ and 33 more |
consultant-2.webp | 600 × 750 | 4:5 | about-2.html, blog/, blog/ and 17 more |
consultant-3.webp | 600 × 750 | 4:5 | about-2.html, blog/, blog/ and 24 more |
consultant-4.webp | 600 × 750 | 4:5 | about-2.html, blog/, blog/ and 24 more |
entry-candidate.webp | 900 × 1125 | 4:5 | index.html |
entry-employer.webp | 900 × 1125 | 4:5 | blog/, blog/, blog/ and 4 more |
hero-person.webp | 817 × 1200 | Transparent cut-out of a person | index.html |
home-2-person.webp | 800 × 1200 | 2:3, Transparent cut-out of a person | home-2.html |
home-3-hero.webp | 1600 × 1000 | 8:5 | case-studies/, case-studies/, elements.html and 1 more |
home-4-hero.webp | 1920 × 1080 | 16:9 | case-studies/, case-studies/, home-4.html |
insight-1.webp | 900 × 600 | 3:2 | 404.html, about-2.html, about-3.html and 59 more |
insight-2.webp | 900 × 600 | 3:2 | blog/, blog/, blog/ and 20 more |
insight-3.webp | 900 × 600 | 3:2 | blog/, blog/, blog/ and 20 more |
insight-4.webp | 900 × 600 | 3:2 | blog/, blog/, blog/ and 12 more |
insight-5.webp | 900 × 600 | 3:2 | about-2.html, blog/, blog/ and 18 more |
insight-6.webp | 900 × 600 | 3:2 | blog/, blog/, blog/ and 10 more |
job-banner.webp | 1920 × 720 | 8:3 | coming-soon.html, employers/, jobs/ |
leader-1.webp | 600 × 750 | 4:5 | about-2.html, about-3.html, about.html and 1 more |
leader-2.webp | 600 × 750 | 4:5 | about-2.html, about.html, elements.html |
leader-3.webp | 600 × 750 | 4:5 | about-2.html, about.html |
leader-4.webp | 600 × 750 | 4:5 | about-2.html, about.html |
sector-construction.webp | 800 × 600 | 4:3 | home-4.html, index.html, sectors/ |
sector-healthcare.webp | 800 × 600 | 4:3 | about-2.html, elements.html, home-4.html and 2 more |
sector-hospitality.webp | 800 × 600 | 4:3 | about-2.html, home-4.html, index.html and 1 more |
sector-logistics.webp | 800 × 600 | 4:3 | about-2.html, elements.html, hire-talent/ and 5 more |
sector-office.webp | 800 × 600 | 4:3 | elements.html, home-3.html, home-4.html and 2 more |
sector-tech.webp | 800 × 600 | 4:3 | home-3.html, home-4.html, index.html and 1 more |
temp-work.webp | 900 × 1125 | 4:5 | blog/, blog/, blog/ and 5 more |
Replacing images
- Keep the file name, or change the
srcin the pages that use it. Keep the shape: the layouts crop withobject-fit, but a photo of the same ratio needs no cropping. - Every
<img>haswidthandheight, 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 inalt. - 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.xmlin 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.htmlis 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, minifystyle.cssandfunctions.jsand 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.
| Feature | Chrome and Edge | Firefox | Safari |
|---|---|---|---|
:has() | 105 | 121 | 15.4 |
light-dark() | 123 | 120 | 17.5 |
color-mix() | 111 | 113 | 16.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:
| Part | Remove |
|---|---|
| Layouts menu | On every page, the block from <!-- Demo Layout Switcher to its <!-- .demo-switch end -->. In style.css, the Demo Layout Switcher rules (section 29). |
| Colours menu | On 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 gone | The 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 note | The .prototype-note paragraph in thank-you.html, once the forms send data. |
| Sample data | The JSON in and , 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.
| Pages | In a CMS |
|---|---|
| Header, mobile menu, footer, cookie banner, modals | Partials, or the theme's header and footer templates; the menus come from the CMS's menu settings, which also mark the current item |
jobs/, jobs/, jobs/ | The job archive (one view, or a setting), with real search, filters and pagination |
jobs/ and its two other layouts | The single job template; the layout becomes a setting |
sectors/, locations/, team/, employers/, case-studies/, hire-talent/ | Archive 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 pages | Page templates or block patterns |
account/, dashboard/ | Signed-in areas for job seekers and for staff, fed from your applications, rota and payroll data |
| Forms | Form 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-facepaths changed: they are relative tostyle.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:
| Name | Version | Licence | In the template | Website |
|---|---|---|---|---|
| Bootstrap | 5.3.8 | MIT | assets/ | getbootstrap.com |
| jQuery | 4.0.0 | MIT | assets/ | jquery.com |
| Font Awesome Free | 7.3.1 | Icons CC BY 4.0, fonts SIL OFL 1.1, code MIT | assets/ | fontawesome.com |
| MapLibre GL JS | 5.24.0 | BSD 3-Clause | assets/ | maplibre.org |
| Red Hat Display and Red Hat Text | SIL Open Font License 1.1 | assets/ | GitHub | |
| Map tiles | Map data © OpenStreetMap contributors (ODbL), tiles from OpenMapTiles | Loaded from OpenFreeMap | openfreemap.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.