Quick start
- Copy the complete
recruitment-agency-templatefolder into your project. - Open
index.htmland replace the Good People name, contact details, hero copy and section copy. - Edit the role articles and matching controls using the instructions below.
- Deploy the folder as static files. There is no build step.
The dependencies load before assets/script.js at the end of <body>:
Code snippet omitted: it ships with the download.
Editing role data
Every role is a complete <article data-role> inside [data-role-list]. Its matching data is on the article itself:
Code snippet omitted: it ships with the download.
data-titleis the concise name announced in the live region.data-skills,data-styleanddata-locationaccept comma-separated values.- Values must match a corresponding control's
data-valueexactly. - The visible tags are ordinary copy. Keep them aligned with the data so people and the score receive the same information.
- Keep
[data-role-peg]if you want a connector to land on the role when it ranks in the top three. - Keep
[data-match-value]for the rolling percentage. data-aboutsupplies the dialog's team introduction.data-responsibilitiesanddata-requirementsare pipe-separated lists used in the full brief.
To add a role, duplicate one article, change its attributes and all visible content, then choose a new authored monogram. The initial no-JavaScript order is the order in the HTML, so put the most useful briefs first. The script can handle any number of roles.
Full role dialog
JavaScript makes each role article keyboard focusable and opens one shared native <dialog> on click, Enter or Space. The script copies the company, title, short summary, current match, salary, contract and visible criteria into the dialog, then fills the long-form sections from the three data attributes above. The application link receives a role-specific email subject automatically.
Edit the reusable process list and closing copy once inside [data-job-dialog]. Escape, the close button and a click on the backdrop all close it; focus then returns to the role that opened it. While open, both native page scrolling and Lenis are paused so wheel and touch input scroll the dialog itself rather than the page behind it. Without JavaScript the cards remain ordinary readable articles and the dialog stays closed.
How the score is calculated
Every open brief starts with a 28-point base. Selected skills are worth 42 points, working style 16 and location 14. Multiple selected skills divide the skill weight evenly, so a role matching one of two chosen skills earns half of those 42 points. The total is converted to a rounded percentage; this keeps every role meaningful while making the selected evidence determine the ranking.
Change those four numbers in scoreRole() in assets/script.js if your matching model needs different priorities.
Editing criteria
A matching control is a native button:
Code snippet omitted: it ships with the download.
There are three supported groups:
| Group | Behaviour | Role attribute |
|---|---|---|
skill |
Multi-select | data-skills |
style |
One choice at a time; active choice can be cleared | data-style |
location |
One choice at a time; active choice can be cleared | data-location |
Add a button by giving it a value used by one or more roles. To change the starting profile, move both aria-pressed="true" and class="is-active" to the desired buttons. JavaScript reads the active defaults from aria-pressed; the class supplies the matching first-paint style.
The script also provides Arrow key, Home and End movement between controls in the same group. Space and Enter activation come from the native <button> element.
The board animation
The board uses Flip.getState() before sorting and Flip.from() after appending all cards in score order. It deliberately leaves absolute: false, so the cards remain in document flow; the role list also holds its current min-height until the animation finishes. This prevents rapid choices from collapsing the board or moving the content beneath it.
The three paths in [data-connectors] are measured after each reorder. The script converts the profile hub and top role pegs into board-relative coordinates, writes cubic SVG paths, then animates their dash offsets. They remain visible throughout the desktop board so the connection effect is present while visitors browse the full list. At widths below 980px the connector overlay is hidden to keep the stacked board clear, while the ranking, percentage update and top-match treatment remain.
Removing sections
Every animation initializer checks for its own root and required children before doing anything. Delete a complete section and remove its navigation link; the rest continues to work.
| Section | Root / ID | Notes |
|---|---|---|
| Hero | [data-hero] |
Includes the masked headline, live-role count, ambient candidate network and ticker. |
| Role board | #roles, [data-match-board] |
Remove as one unit, including the overlay SVG. |
| Method | #method |
The SVG route draws on scroll; the three steps and proof strip remain semantic content. |
| Stories | #stories |
Candidate and employer quote stack. |
| Employer brief | #brief |
Mail link and response promise. |
| Contact footer | #contact |
Compact contact details; no script dependency. |
Individual roles can be removed without changing the script. If fewer than three remain, unused connector paths are cleared automatically.
Palette
The identity is carried by six solid tokens. Keep each RGB triple in step with its hex because every translucent border, wash, shadow and dim text value uses those triples.
Code snippet omitted: it ships with the download.
The buyer-facing comment at the top of assets/style.css records the measured ratios for solid text, dim text, active controls and the top-match wash. Keep these constraints when reskinning:
- navy and navy at
.72are the only text colours on chartreuse, peach, paper and white; - white and white at
.76are the text colours on navy; - white is safe on cobalt;
- cobalt can carry match percentages on white or the top-match wash, but is banned as small text on chartreuse because the pair has too little margin;
- chartreuse and peach never carry white text.
Accessibility and fallbacks
- Native controls: every criterion is a real button with
aria-pressed, visible focus, touch activation and ordinary keyboard activation. Role articles receive button semantics only after the working dialog is available. - Keyboard navigation: Arrow keys move within a criteria group; Home and End jump to its first and last controls.
- Live updates: one polite atomic live region announces only the best two role names and percentages after a choice. Individual rolling values have accessible percentage labels but do not each announce.
- Reduced motion: CSS restores every gated reveal before paint. The ticker, ambient hero network, route draw and dialog transitions become static; matching order, scores and connectors update instantly; the live role count displays its final value.
- No JavaScript: the head gate never applies, matching controls and connector SVG remain hidden, and every fully detailed role appears in the authored default order. A short note explains the static board.
- Blocked CDN:
assets/script.jsremoveshas-jsif GSAP, ScrollTrigger or Flip is missing, restoring the same plain document. - Contrast: all reading text clears 4.5:1 at its actual size and surface. Exact ratios and colour bans are documented at the top of
assets/style.css.
Dependencies
- GSAP 3.15.0 core
- ScrollTrigger 3.15.0 for section reveals
- Flip 3.15.0 for role reordering
- Lenis 1.3.17 for optional smooth scrolling
- Google Fonts: Zilla Slab and DM Sans
Lenis is optional. Remove its CDN tag and the marked Lenis setup block near the top of assets/script.js; ScrollTrigger and the board continue to work with native scrolling.
Image assets
None are required. Candidate marks, role stamps, connectors and all other visual details are CSS or inline SVG, so there are no image licences, external photo URLs or files to replace.
Worked examples, the events and programmatic API, and the class reference ship with the download, alongside the full source.