GODRICH

9 Event Landing Page Templates — Copy-Paste

Event landing page templates are ready-to-paste hero, schedule, speaker, and pricing sections for conference and meetup pages, and one of the nine below counts

Auto-plays · click a tile to jump to its section · all nine in one zip

The nine aren't ranked by popularity — they're ordered the way a visitor actually scrolls a landing page. A hero grabs attention first, a timeline sets expectations, a speaker grid builds trust, a venue block hands over logistics, a pricing table asks for a decision, a sponsor bar reinforces trust once more, an FAQ clears the last doubts, a register CTA converts, and a countdown band nails down why it has to happen now. Every photo, logo, and avatar placeholder below is a shape built from this site's own ink, blue, and cream tokens — nothing here is a real brand or a real face. Swap in an actual logo file or a photo and the layout, transitions, and JavaScript keep working exactly as they are.

01Event hero

Three blurred circles drift behind the stage on a continuous translate-and-scale loop while the headline, date pill, and CTA row hold still in front of them. The "save this event" bookmark button on the right actually flips aria-pressed and fills its icon on every real click, so it fits a conference or meetup landing page, or the hero of a paid ad landing page pointed at one event.

transformopacityaria-pressed
.eh__orb--1 { animation: eh-float-a 2s ease-in-out infinite; }
@keyframes eh-float-a {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50%      { transform: translate($sp-10, -$sp-8) scale(1.5); }
}
.eh__save[aria-pressed="true"] {
  background: rgba(255, 247, 230, .12);
  border-color: $subject-cream;
}
.eh__save[aria-pressed="true"] .eh__save-ic {
  opacity: 1;
  color: $color;
  transform: scale(1.15);
}

02Schedule timeline

Clicking a stop on the vertical line fills the progress track up to that point with a real scaleY transform and rings the newly active dot with a box-shadow pulse, while an idle loop cycles the same four stops on its own until someone clicks. It works well for a same-day event agenda or a conference schedule block sitting under the hero.

scaleYclickaria-current
.tl__fill {
  position: absolute; inset: 0;
  transform: scaleY(.25);
  transform-origin: top;
  background: $color;
  transition: transform $duration $easing;
}
.tl__stop[aria-current="step"] .tl__dot {
  background: $color;
  transform: scale(1.3);
  box-shadow: 0 0 0 4px rgba(23, 20, 26, .14);
}

03Speaker grid

Six cards fade and tilt into place one after another on load, each settling from a slight rotation back to flat. Clicking a card expands only that card's one-line bio with a max-height transition while the other five stay closed, which suits a speaker lineup, a team page, or a panel of judges.

staggergrid-template-columnsclick
.sg.is-demo .sg__card { animation: sg-in 2s $easing infinite; }
@keyframes sg-in {
  0%   { opacity: .7; transform: translateY(6px) rotate(-1.5deg); }
  18%  { opacity: 1; transform: translateY(0) rotate(0deg); }
  86%  { opacity: 1; transform: translateY(0) rotate(0deg); }
  100% { opacity: .7; transform: translateY(6px) rotate(-1.5deg); }
}
.sg__card.is-open .sg__bio { max-height: 60px; opacity: 1; }

04Venue block

Three real role="tab" buttons for subway, bus, and driving control which directions paragraph is visible, sliding an underline indicator with translateX and cross-fading the panel text with opacity. A pin on the map placeholder keeps rippling in the background the whole time, which is exactly the shape a "getting here" section or a store-locator card needs.

opacityaria-selectedclick
tabs.forEach(function (t) {
  t.addEventListener('click', function () {
    tabs.forEach(function (o) { o.setAttribute('aria-selected', 'false'); });
    t.setAttribute('aria-selected', 'true');
    ind.style.transform = 'translateX(' + (Number(t.dataset.i) * 100) + '%)';
    panels.forEach(function (p, i) {
      p.style.opacity = String(i === Number(t.dataset.i) ? 1 : 0);
    });
  });
});

05Ticket pricing

The middle card carries a "popular" badge and a looping box-shadow glow that never stops, while the early-bird/regular role="switch" at the top cross-fades all three price figures at once with opacity the instant it's toggled. This is built for a ticket sales page or any tiered pricing comparison where the toggle needs to feel instant rather than reloaded.

scaleopacityaria-checked
.tp__price-a, .tp__price-b {
  position: absolute; inset: 0;
  transition: opacity $duration $easing;
}
.tp__price-b { opacity: 0; }
.tp__switch[aria-checked="true"] ~ .tp__cards .tp__price-a { opacity: 0; }
.tp__switch[aria-checked="true"] ~ .tp__cards .tp__price-b { opacity: 1; }
.tp__card--pop { animation: tp-glow 2.4s ease-in-out infinite; }

06Sponsor logo bar

Eight placeholder logo blocks — shapes, not real logos — sit in a track duplicated end to end so a translateX(-50%) loop scrolls forever with no visible seam, and hovering or tapping the pause button stops it in place. It's the standard spot for a sponsor row, a partner list, or a "featured in" media bar.

translateX(-50%)animation-play-statepointerenter
// the track itself skips gap — each logo gets margin-right instead
.sb__track { display: flex; width: max-content; animation: sb-scroll 14s linear infinite; }
.sb__logo { flex: 0 0 auto; margin-right: $sp-6; }
@keyframes sb-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

07Event FAQ

Only one of the three questions can be open at a time — clicking a question expands its answer with a grid-template-rows: 0fr → 1fr transition and rotates the chevron, and opening one closes whichever was open before it. Ticket, refund, and parking questions are exactly what this single-open accordion pattern is built to answer without the page growing tall.

grid-template-rowsaria-expandedclick
.fq__a-wrap {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows $duration $easing;
}
.fq__item.is-open .fq__a-wrap { grid-template-rows: 1fr; }
.fq__a { min-height: 0; overflow: hidden; }

08Register CTA

Submitting the form runs a real regex check on the email address rather than pretending to validate. A passing address draws a checkmark onto the button with stroke-dashoffset and swaps the label to "done," while a failing one shakes the input left and right with translateX — nothing about the input itself moves before that submit happens.

stroke-dashoffsetopacitysubmit
form.addEventListener('submit', function (e) {
  e.preventDefault();
  var ok = /^\S+@\S+\.\S+$/.test(input.value);
  if (ok) {
    form.classList.add('is-done');
    done.textContent = 'Registered — check your inbox for confirmation.';
  } else {
    input.classList.remove('is-shake');
    void input.offsetWidth;
    input.classList.add('is-shake');
    done.textContent = 'Enter a valid email address.';
  }
});

09Countdown band

Four number cards count down to a real deadline set exactly 7 days, 4 hours, 20 minutes, and 15 seconds from the moment the page loads, updating every second through setInterval. The seconds card nudges up and scales slightly on every tick rather than flipping — a deliberate choice covered in the trap below — which makes it a good fit for a pre-event countdown band or an early-bird deadline banner.

translateYsetIntervalDate
var target = Date.now() + ((7 * 24 * 60 * 60) + (4 * 60 * 60) + (20 * 60) + 15) * 1000;
function tick() {
  var diff = Math.max(0, target - Date.now());
  var s = Math.floor(diff / 1000);
  els.d.textContent = pad(Math.floor(s / 86400));
  els.h.textContent = pad(Math.floor((s % 86400) / 3600));
  els.m.textContent = pad(Math.floor((s % 3600) / 60));
  els.s.textContent = pad(s % 60);
}
tick();
setInterval(tick, 1000);

Where it breaks — the trap

The real trap across all nine wasn't any one animation — it was the 320×200 breakpoint. At the full 480×300 canvas every section behaved, but five of the nine (speaker grid, venue block, ticket pricing, FAQ, register CTA) grew to 260–450px tall once the width dropped to 320px, blowing past the 200px height budget. Folding the speaker grid to two columns made it worse, not better: six cards at two per row become three rows, which is taller than three cards per row ever was. The fix that actually worked was keeping three columns everywhere and hiding or shrinking only secondary text — role labels, venue descriptions, ticket line items — inside a @media (max-width: 340px), (max-height: 220px) block.

The countdown seconds card also went through a real rewrite. The first version flipped it with rotateX(0deg → -90deg → 0deg) for a coin-flip effect, but without a perspective value on the parent, the card went completely flat exactly at the 90-degree midpoint — MDN's transform-style reference explains why a 3D rotation collapses to nothing without a perspective context, and a poster screenshot landing on that frame showed a flat dash instead of a digit. Swapping to a translateY + scale nudge removed the flat frame entirely while keeping a visible tick. The sponsor logo bar has its own version of this problem: give the duplicated track a gap instead of margin-right on each logo and the seam between the two copies comes up short by gap ÷ 2, so the infinite scroll visibly jumps once per loop. With both fixes in and the 320×200 breakpoint sorted, open the zip with 5ngtcz6h typed exactly as it appears here and all nine behave the way this page describes.

Accessibility

Every one of the nine respects prefers-reduced-motion: reduce, but each keeps its actual state rather than just going still — the schedule fill stays at whatever point it reached, the FAQ answer stays open once expanded, and the countdown digits keep updating every second while only the seconds card's nudge and the background glow turn off. The venue block (04) is a real role="tablist" with role="tab" and live aria-selected, built to the keyboard behavior in the W3C ARIA Authoring Practices tabs pattern. The register CTA's result text (08) sits in a role="status" region so a screen reader announces success or failure the moment the form submits, and the countdown (09) carries role="timer" with aria-live="off" so the once-a-second digit change never interrupts whatever else is being read.

More templates and layout sections live on the template category hub, and what this site does and doesn't sell is on the about page.

FAQ

Can I drop real photos and a real logo into these templates?

Yes — that's the point. Every photo, avatar, and logo across all nine is a CSS shape built from this site's own tokens, not a real image file, so swapping in an actual <img> or a brand's logo file is a straight replacement that doesn't touch the layout or the JavaScript. The color tokens in demo-tokens.scss can stay as they are or get swapped for a brand palette without breaking anything.

Does the countdown band actually count down, or is it just decoration?

It actually counts down. The target time is set to exactly 7 days, 4 hours, 20 minutes, and 15 seconds past the moment the page loads, and setInterval recalculates the remaining days, hours, minutes, and seconds every second from Date.now(). Swapping in a real event date is a one-line change to that target value — the React port takes the same number as a targetMs prop.

How different is the React version from the plain CSS one?

The behavior is identical. Active tab, open accordion item, and the toggled switch all live in useState instead of DOM attributes, and the three SCSS variables — duration, easing, color — come in as component props that get forwarded to CSS custom properties. The countdown component runs the same setInterval tick logic inside a useEffect with its own cleanup, so the two versions tick in lockstep.

Enter the archive password

The password is inside this article. You will find it as you read.