section-030

Desk Directory Contact

Vault only: not sold separatelyGet the Vault

A Swiss grid contact section: pick what your enquiry is about and a column of ink crosses the grid to reveal who answers, their direct line and which door to use.

intermediate
9 more details
accessible-tabsclip-path-revealsliding-indicator-tabsinterruptible-transitionsform-validationprogressive-enhancementkeyboard-navigationcontainer-queriesresponsive-section

This section reads better at your own screen size than in the frame below:

Released

About this section

Desk Directory Contact is a contact section for organisations where different questions go to different people and often to different doors. It is set like a Swiss poster on a flat vermilion field: a visible 12-column grid, one large grotesk set flush left, black and white photography cropped to the columns and a desk index laid along the grid.

Read the full section overview

Choosing a desk sends a single column of ink across the stage one grid column at a time. Behind it the chosen desk appears: its photograph, a direct line set large, an email address, who answers and which entrance to use in person. The black index marker travels in the same steps. Change your mind halfway and the shutter reverses; pick a third desk and the current sweep finishes quickly before the next one runs. Below, a real form routes the message to the chosen team, with inline validation and a documented endpoint.

The fictional Farrant Hall example is a concert hall with a box office, access line, learning team, hire office and stage door. The same structure suits a university, a hospital, a council office, a museum or any organisation with more than one front desk. Replace the fictional copy, generated concept photography and example contact details with your own.

Desk Directory Contact - website section preview

What's included

10 items
  • Visible 12-column grid that the whole layout, the index and the shutter snap to
  • A column of ink crosses the stage a column at a time, revealing the chosen desk behind it
  • Index marker moves in the same steps, over an inverted copy of the labels so text never clashes
  • Reversing mid-sweep runs the shutter back; a third choice finishes the sweep quickly and queues the next
  • Each desk shows who answers, a large tap-to-call number, email, hours and the entrance to use in person
  • Form routes to the chosen desk, with a routing line, desk-specific hint and inline validation
  • Documented POST endpoint; with none set the form says plainly that nothing was sent
  • Works without JavaScript: desk links show their own panel and the form submits natively
  • 4-column phone layout with the index as a short two-column set directly above the panel
  • Independent instances, change event, programmatic go() and exact teardown

Perfect for

4 use cases
  • Concert halls, theatres and venues with a box office, access line and stage door
  • Universities and schools routing admissions, accommodation and press enquiries
  • Hospitals, councils and public services with separate desks and entrances
  • Museums and galleries with groups, hire, press and visitor information

How it works

3 sections

Each desk is an article with its heading, photograph and a list of contact facts, and a link in the index points at it. Without the script the first desk shows and each index link reveals its own panel through the URL fragment, so every desk stays reachable. With the script the links become ARIA tabs with arrow-key, Home and End navigation.

All panels share one grid cell, so the stage keeps the height of the tallest desk and nothing below it jumps. Choosing a desk starts one GSAP tween of a position measured in grid columns. The script reads the real column widths and gutter from the visible grid, and on each update clips the outgoing panel ahead of the shutter and the incoming panel behind it. Each column step holds briefly and then moves, so the shutter reads as a mechanism rather than a glide. The index marker interpolates between the two tab cells in the same steps and carries an inverted copy of the labels, so the text under it changes colour exactly at its edge.

Choosing the previous desk mid-sweep reverses the same tween; choosing a third speeds the current sweep up and queues the new one, so fast input always settles on the last choice. Reduced motion, or no GSAP, makes every change instant, including when the preference changes while the page is open. The form validates on submit, marks fields with aria-invalid and linked messages, and POSTs FormData to the URL in data-dsk-endpoint.

Difficulty Intermediate
Includes HTML + JS + CSS source, documentation, AI setup prompt, lifetime updates

Vault only

Get the Vault to use this section.

The Vault includes Desk Directory Contact, the HTML, CSS and JavaScript source, the full documentation, an AI setup prompt for your editor, and every update we ship to it. Standard license: unlimited personal and commercial projects. Every paid product is tested for desktop and mobile layouts, reduced-motion handling, animation cleanup and keyboard controls wherever there is something to operate. Sections are available only in the Vault for now while the collection is small.

Documentation

Quick Start

  1. Copy assets/style.css, assets/script.js and assets/img/ into your project.
  2. Load the font, the stylesheet, GSAP 3.15.0 and the script:

Code snippet omitted: it ships with the download.

  1. Copy the markup between the Desk Directory Contact: copy from here and copy to here comments in index.html. Everything outside <section class="dsk"> is demo page.

GSAP is optional: without it every change is instant. Without JavaScript the first desk shows, each index link shows its own desk, and the form submits natively to its action.

Make it yours

Text and links

  • Masthead: the four .dsk__mast paragraphs (name, subject, address, switchboard). Each sits on three grid columns; remove one and the rest keep their columns.
  • Title: .dsk__title (an h2). Change the tag freely; styles use the class. It is set on one line per <br>; keep lines short, as the size is large on purpose.
  • Lede: .dsk__lede.
  • Index label: .dsk__index-label.
  • Each desk is one <article class="dsk__panel">:
    • .dsk__name (an h3) and .dsk__about.
    • .dsk__facts: one <div class="dsk__fact"> per fact. The dsk__fact--call modifier sets the number large; tel: links use the full international number. Delete or add facts freely.
    • .dsk__write: the link to the form. It selects this desk and moves focus to the form.
    • data-dsk-team and data-dsk-email: used in the form's routing line ("Goes to ...").
    • data-dsk-hint: the help text shown under the message field for this desk.
  • Fine print: .dsk__fine. Remove it once the content is yours.

Photos

One photo per desk, in .dsk__figure:

Desk File Size
Tickets assets/img/tickets.webp 1536 x 1024
Access assets/img/access.webp 1536 x 1024
Schools assets/img/schools.webp 1536 x 1024
Hiring the hall assets/img/hire.webp 1536 x 1024
Stage door assets/img/stage-door.webp 1536 x 1024

To replace one, save any ordinary photo (1400 to 2000 px wide works well), change src, width, height and alt on its <img>, and adjust style="object-position: 50% 50%" to keep the subject in frame. Frames are cropped to --dsk-photo-ratio (3:2), so portrait or square photos are cropped too; set object-position so the person or doorway stays in view. The first desk's photo has fetchpriority="high"; the rest are loading="lazy". The demo photos are black and white, which suits the flat colour field; colour photos work as well.

Adding, removing or reordering desks

Desks are matched by key: the index link's data-dsk-for, the panel's data-dsk-key and the form option's value must be the same word.

  • Add: copy a panel and an index link, give both a new key and a new id and href, and add a matching <option> to the form's select.
  • Remove: delete the panel, its link and its option.
  • Reorder: reorder the panels, links and options the same way. Numbers in the index are automatic, and the shutter's direction follows panel order.

Five desks line up exactly with columns 3 to 12. Two to eight work: other counts share that span equally. With a single desk, delete the index; the panel and form still work.

Brand variables

All on .dsk:

Variable Default Use
--dsk-ground #f25c34 The colour field, and the text on black buttons
--dsk-ink #111111 Type, rules, the shutter and the active desk
--dsk-field #ffffff Form field fill
--dsk-rule rgba(17,17,17,.16) The visible grid lines
--dsk-font Host Grotesk Every text role
--dsk-max 1440px Maximum width including side padding
--dsk-pad / --dsk-gap fluid Side padding and column gutter
--dsk-photo-ratio 3 / 2 Photo frame proportion

Rebrand example, a hospital's outpatients desk in green:

Code snippet omitted: it ships with the download.

Check contrast when you change the ground: body text is --dsk-ink on --dsk-ground, and buttons use --dsk-ground on --dsk-ink; both need 4.5:1. The default pair measures 5.7:1. To hide the visible grid, set --dsk-rule: transparent; the layout keeps its columns.

Behaviour and options

  • data-dsk-duration="0.72" on .dsk: seconds for one full sweep.
  • root.deskDirectory.go('access') selects a desk; { instant: true } skips the sweep.
  • root.addEventListener('dsk:change', e => e.detail.key) fires on each new choice.
  • root.deskDirectory.destroy() removes everything the script added (tabs roles, marker, shutter, form handling) and restores the plain links; DeskDirectory.mount(root) starts it again, for instance after injecting the markup later.
  • Choosing the previous desk during a sweep reverses it; choosing a third lets the current one finish quickly and then runs the next. Input always settles on the last choice.
  • A link to #<panel id> in the page URL opens that desk first.

The form

Set data-dsk-endpoint on the <form> to a URL that accepts a POST of FormData (a form service such as Formspree, Basin or your own handler), and set action to the same URL for visitors without JavaScript. Fields posted: desk, reference, name, email, message.

With no endpoint, the form validates and then says plainly that nothing was sent. Nothing in this section stores or sends data by itself, and there is no backend included.

Accessibility and integration

  • The index becomes an ARIA tablist: Tab reaches the selected desk, arrow keys, Home and End move and select. Links, buttons and fields have visible focus rings.
  • Every desk is readable without JavaScript. Reduced motion makes changes instant, including if the setting changes while the page is open.
  • Form errors appear next to their field, are linked with aria-describedby, set aria-invalid, and focus moves to the first one. The result is announced from a role="status" line.
  • The title is an h2 and desk names are h3s; change the tags to fit your page.
  • The section is full width with its own background and needs no sticky or scroll behaviour. It works in narrow columns: below 720 px of its own width it switches to a 4-column grid.
  • Two instances need different ids on panels and form fields; the script scopes everything else to each section.

Dependencies and credits

  • GSAP 3.15.0 (optional; free for all uses).
  • Host Grotesk from Google Fonts, SIL Open Font License.
  • Photographs are AI-generated concept images made for this demo, provided for use with this section. Farrant Hall, its people, numbers (Ofcom drama range) and addresses are fictional.

Worked examples, the events and programmatic API, and the class reference ship with the download, alongside the full source.