GODRICH
#css-animation#button#loader#transition#scroll#dashboard#ui#design-trends

9 Landing Page Sections That Build Trust

Landing page sections like these are the trust-building pieces that usually end up scattered across templates.

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

The order of these website landing page sections follows how a visitor's trust actually builds, not a popularity ranking. A metric counter opens with scale, a logo cloud shows who else already uses the product, a comparison table lays out the plan differences, a team grid puts real people behind the brand, a newsletter band asks for a lightweight next step, an integration grid lists what it already connects to, a roadmap shows where the product has been and where it's going, a press/awards section adds third-party proof, and a contact form closes with an actual question. Every avatar, logo, and outlet name here is a shape drawn from this site's own ink, blue, and cream tokens — swapping in real assets later is a straight drop-in that leaves the grid and the JavaScript untouched. The same section kit aimed at a limited-time push is Promotion Landing Page Templates, and the piece that puts a human face on trust is covered more closely in Profile Card Design Styles.

01Key-metric counter row

What you see in this landing page sections design

Three numbers count from zero to their real target with requestAnimationFrame the instant the page loads, each one starting a beat after the last.

Key-metric counter row
Open in a new tab

01 · Key-metric counter row — Measured area 6.406% · moving frames 23/23Original by GODRICH · SCSS and React ship in the zip · See the password

requestAnimationFramecountertransform

Where to look in the code

The trend icon above each number keeps a gentle bob going so the row reads as alive rather than static.

document.querySelectorAll('.stats__n').forEach(function (el, i) {
  var target = Number(el.getAttribute('data-target'));
  var DUR = 1100, start = null, delay = i * 140;
  function frame(ts) {
    if (!start) start = ts;
    var t = Math.max(0, ts - start - delay);
    var p = Math.min(1, t / DUR);
    var eased = 1 - Math.pow(1 - p, 3);
    el.textContent = Math.round(eased * target).toLocaleString('en-US');
    if (p < 1) requestAnimationFrame(frame);
  }
  requestAnimationFrame(frame);
});

02Logo cloud / trusted-by bar

What happens on screen

The logo row scrolls without a seam, and pressing the button flips a real aria-pressed value that actually pauses the scroll and lets it run again.

Logo cloud / trusted-by bar
Open in a new tab

02 · Logo cloud / trusted-by bar — Measured area 5.088% · moving frames 23/23Original by GODRICH · SCSS and React ship in the zip · See the password

translateX(-50%)margin-rightaria-pressed

How to read the code

The track is the same six logos pasted twice, so the loop point never shows a jump.

.lc__track {
  display: flex;
  width: max-content;
  animation: lc-scroll 9s linear infinite;
}
.lc__track li {
  flex: 0 0 auto;
  margin-right: 24px; // margin-right instead of gap
}
@keyframes lc-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

03Feature comparison table

What moves

Clicking a plan name flips aria-pressed and genuinely scales up and highlights that column's check and cross icons.

Feature comparison table
Open in a new tab

03 · Feature comparison table — Measured area 15.99% · moving frames 7/23Original by GODRICH · SCSS and React ship in the zip · See the password

aria-pressedscaleclick

What to change

The two columns also alternate every second on their own, so the difference is visible even before anyone clicks.

function select(plan) {
  document.querySelectorAll('.fc__plan').forEach(function (b) {
    var on = b.getAttribute('data-plan') === plan;
    b.classList.toggle('is-on', on);
    b.setAttribute('aria-pressed', String(on));
  });
  document.querySelectorAll('.fc__cell').forEach(function (c) {
    c.classList.toggle('is-on', c.getAttribute('data-plan') === plan);
  });
}

04Team members grid

What you see

Clicking a member card or pressing Enter flips aria-expanded and actually expands a one-line bio through grid-template-rows.

Team members grid
Open in a new tab

04 · Team members grid — Measured area 35.494% · moving frames 13/23Original by GODRICH · SCSS and React ship in the zip · See the password

aria-expandedgrid-template-rowsclick

Where to look in the code

The avatar scales and tilts slightly while its card is open, so it's obvious at a glance which member is expanded.

document.querySelectorAll('.tm__head').forEach(function (btn) {
  btn.addEventListener('click', function () {
    var card = btn.closest('.tm__card');
    var open = btn.getAttribute('aria-expanded') === 'true';
    btn.setAttribute('aria-expanded', String(!open));
    card.classList.toggle('is-open', !open);
  });
});

05Newsletter signup band

What happens on screen

Typing an email and submitting runs it through a real regular expression, and on a pass the checkmark actually draws itself via stroke-dashoffset while the button relabels to "Subscribed".

Newsletter signup band
Open in a new tab

05 · Newsletter signup band — Measured area 0.22% · moving frames 16/23Original by GODRICH · SCSS and React ship in the zip · See the password

정규식stroke-dashoffsetsubmit

How to read the code

A bad format shakes the input left and right instead of failing silently.

var RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
form.addEventListener('submit', function (e) {
  e.preventDefault();
  if (RE.test(input.value)) {
    form.classList.add('is-done');
    msg.textContent = 'We sent a confirmation to ' + input.value + '.';
  } else {
    input.classList.add('is-shake');
    msg.textContent = 'Please check the email format.';
  }
});

06Integration partners grid

What moves

Pressing a connect button flips aria-pressed and genuinely slides the dot to the right while the label switches to "Connected".

Integration partners grid
Open in a new tab

06 · Integration partners grid — Measured area 0.339% · moving frames 16/23Original by GODRICH · SCSS and React ship in the zip · See the password

aria-pressedtranslateXclick

What to change

The dot only moves inside its own track, so it never overlaps the label text next to it.

document.querySelectorAll('.ig__toggle').forEach(function (btn) {
  btn.addEventListener('click', function () {
    var on = btn.getAttribute('aria-pressed') === 'true';
    btn.setAttribute('aria-pressed', String(!on));
    btn.querySelector('.ig__state').textContent = on ? 'Connect' : 'Connected';
  });
});

07Timeline / roadmap

What you see

The spotlight advances to the next quarter on its own, and clicking a step or tabbing to it moves the spotlight by a real, measured translateY distance instead of a guessed one.

Timeline / roadmap
Open in a new tab

07 · Timeline / roadmap — Measured area 4.467% · moving frames 6/23Original by GODRICH · SCSS and React ship in the zip · See the password

setIntervalgetBoundingClientRecttranslateY

Where to look in the code

Finished and upcoming quarters use two different icons so the split is obvious without reading the text.

function moveTo(idx) {
  i = idx;
  var top = steps[idx].getBoundingClientRect().top - list.getBoundingClientRect().top;
  spot.style.transform = 'translateY(' + top + 'px)';
  steps.forEach(function (s, n) { s.classList.toggle('is-active', n === idx); });
}

08Awards / press mentions

What happens on screen

Clicking an outlet name flips aria-expanded and genuinely expands that outlet's quote, one at a time.

Awards / press mentions
Open in a new tab

08 · Awards / press mentions — Measured area 20.544% · moving frames 11/23Original by GODRICH · SCSS and React ship in the zip · See the password

aria-expandedgrid-template-rowsclick

How to read the code

The outlets also cycle open on their own, so every quote surfaces even if nobody clicks anything.

function openOnly(idx) {
  btns.forEach(function (b, n) {
    var on = n === idx;
    b.setAttribute('aria-expanded', String(on));
    b.closest('.ap__badge').classList.toggle('is-open', on);
  });
}

09Contact form (split layout)

What moves

Filling in name, email, and message and sending it makes the paper-plane icon actually fly off and fade out while the button relabels to "Sent".

Contact form (split layout)
Open in a new tab

09 · Contact form (split layout) — Measured area 1.571% · moving frames 7/23Original by GODRICH · SCSS and React ship in the zip · See the password

정규식translate+opacitysubmit

What to change

Only the field that's empty or fails the regex check shakes, not the whole form.

inputs.forEach(function (inp) {
  if (!inp.value.trim() || (inp.type === 'email' && !RE.test(inp.value))) {
    ok = false;
    inp.classList.add('is-shake');
  }
});
if (ok) {
  form.classList.add('is-sent');
  msg.textContent = 'Got it — we reply within one business day.';
}

Where it breaks — the trap

Three real snags came up while building these nine. The first was the logo cloud (02). The track pastes six logos twice and loops with translateX(-50%), and the first pass spaced the items with gap. Twelve items only have eleven gaps between them, so -50% lands half a gap short and the row visibly jumps once per loop. Swapping gap for margin-right on each item removed the seam completely.

The second came from the 320×200 phone check. The team grid (04) and the contact form (09) originally switched to flex-direction: column under the narrow breakpoint, which stacked the panels and made the layout taller, not shorter — the measured height came back over the viewport. Keeping the row layout and shrinking font size and padding instead brought both back under the limit.

The third was the connect toggle in the integration grid (06). The dot originally sat inline with the "Connect" / "Connected" label and moved with transform: translateX alone, so at the "on" position it visually overlapped the first letter of the label. Wrapping the dot in its own small track and positioning the dot inside that track removed the overlap.

Accessibility

Proving consistency with numbers gets its own treatment as a contribution grid in Habit Tracker UI. All nine, in the exact code you get from the zip once you open it with rghhpe4v, turn off decorative motion under prefers-reduced-motion: reduce while keeping the state itself — the counter row (01) drops the icon bob but keeps counting up since the number is information, and the logo bar (02) stops scrolling while the pause button still works. The comparison table (03) and integration grid (06) carry state through aria-pressed, while the team grid (04) and press mentions (08) carry their expanded state through aria-expanded. The newsletter band (05) and contact form (09) report their result through role="status" so a screen reader announces success or failure right away. The grid-template-rows: 0fr → 1fr reveal follows the standard track-sizing syntax documented on MDN's grid-template-rows page, and prefers-reduced-motion itself follows MDN's reference.

If event and press-room sections are what you're after, the template collection covers those, and the about page has more on who builds this site.

FAQ

In these landing page sections examples, does the logo bar (02) actually scroll, or is it a static image?

It actually scrolls — a translateX(-50%) CSS animation loops it, and the logo list is pasted exactly one extra time so the loop point never shows a seam. Pressing the pause button flips animation-play-state to paused for real. Stacking press coverage as evidence is written up in Media Page Templates.

Does the React version behave the same as the CSS version?

Yes. Every piece of state — expanded, connected, highlighted — lives in useState, and the three variables (duration, easing, color) come in as props and get passed straight through as CSS variables. The roadmap's (07) auto-advance and the contact form's (09) auto-focus cycle both run the same logic inside useEffect.

Does the contact form (09) actually send an email anywhere?

No — the demo itself only runs the format check and shows the sent state; there's no real delivery server behind it. Intercepting the form's submit event and validating with a regular expression is as far as this template goes, and wiring in a real API call at that point lets you keep the rest of the validation and display logic as-is.

Enter the archive password

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