Arc CTA Section

( Cta / Landing / Marketing / Gallery )

A closing call-to-action section with an arc of images curving over the headline, a pill button and a three-up reassurance row.

Live preview and source code for Arc CTA Section

Ready to make something worth sharing

Everything you need to get started is already here — no setup, no waiting.

  • Quick to start

    Up and running in a few minutes.

  • Made to fit

    Adapts to the way you already work.

  • Here to help

    Real people answer, usually same day.

The call-to-action section a page ends on: one line, one button, and an arc of images curving over the top of both. It is the pre-footer slot — the last thing someone reads before the links and the copyright — and the arc is doing the work a wall of screenshots usually does, without asking anyone to study it. The cards are placed by angle around a single pivot rather than positioned by hand, so the sweep stays even at any count, and it ships with placeholder tiles so the section looks right before the artwork exists.

Installation

Copy the source from the Code tab above into your project as ArcCtaSection.tsx. Its styles are a <style> block of acs- prefixed classes that travels with the file, so there is no stylesheet to import and no Tailwind config to change.

It imports framer-motion for the entrance and lucide-react for the arrow and the placeholder icon:

Terminal
npm install framer-motion lucide-react

The headline is set in Instrument Serif, and the section requests that font itself through three <link> tags at the top of its markup rather than through a global stylesheet. That is deliberate: the request goes out on the pages that render this section and nowhere else. Delete those three tags and the stack falls back to the platform serif, which is the whole of what it takes to drop the dependency.

The file starts with "use client" — it uses hooks, so in the Next.js app router it has to stay a client component.

Usage

Every prop is optional, and the defaults are deliberately generic — replace all of them. Pass your images in the order they should run around the arc, left to right:

Example.tsx
import ArcCtaSection from "./components/ArcCtaSection";

export default function Example() {
    return (
        <ArcCtaSection
            images={["/work/1.jpg", "/work/2.jpg", "/work/3.jpg", null, null]}
            headline="Ready to start your first project"
            ctaLabel="Book a call"
            ctaHref="/contact"
            features={[
                { title: "No commitment", description: "Cancel any time, no notice period." },
                { title: "Fixed pricing", description: "One number, agreed before we begin." },
                { title: "Fast turnaround", description: "First draft inside a week." },
            ]}
        />
    );
}

The number of cards is the length of images, and they spread evenly between startAngle and endAngle (−85° and 95° by default, measured clockwise from the top). Any entry that is null renders the grey placeholder tile, so you can fill the arc in as the pictures arrive.

With ctaHref the button is an <a>. Without it you get a <button type="button"> that does nothing when clicked — wire it up, or give it an href. features takes any number of items, three being what the row is drawn for; pass [] to drop it and ctaLabel={null} to drop the button.

When to reach for it

The bottom of a long page, where someone has read everything and needs one obvious next step. The three short columns under the button are the last objections — price, commitment, effort — answered in a sentence each.

Any page with a body of visual work behind it: a studio, a photographer, a product with a gallery, a tool that makes things. The arc says look how much of this there is in a way a grid of thumbnails at the bottom of a page never manages.

A section that has to hold up at any width. Sizes are set in container query units, so the arc is scaled from the width of the section rather than the window — it keeps its proportions inside a narrow column, and does not need a viewport to itself.

When not to

At the top of a page. The headline is an <h2>, the arc reads as a summing up rather than an opening, and the whole thing assumes a reader who has already been convinced. Modern Hero is the one that opens.

If you have fewer than about six images. The sweep is fixed, so a short array spaces the cards far apart and the curve stops reading as a curve. A plain centred headline and a CTA Button will look deliberate where a sparse arc looks broken.

If the images are the content. They are decoration — the whole arc is aria-hidden, every tile is cropped to a tall 3:4 and rotated, and the ones at the bottom fade out mid-image. Anything a visitor is meant to study or click belongs in a gallery, not here.

Accessibility

The arc is marked aria-hidden, so a screen reader gets the headline, the sentence, the button and the feature list and nothing else. If your images carry meaning, remove that attribute and give each one a real alt — the component renders alt="" on every card.

The headline is an <h2> and each feature title an <h3>, which is the right shape for a section closing a page rather than opening one. The features are a real <ul>, so the three points are announced as a list of three.

The entrance is gated on prefers-reduced-motion through framer-motion’s useReducedMotion: with the setting on, the cards and the copy start at their final values instead of fading in, and the button drops its hover transition.

Notes

Each card is rotated by its own angle, which is what makes the ends of the arc lie on their sides — a card at 90° reads as landscape while the ones at the top read as portrait. Crop for the top of the arc and let the ends fall where they land, or narrow the sweep with startAngle and endAngle.

The gap between two cards is the arc step minus the card, so adding images without widening the sweep eventually closes it: past about fourteen the corners of neighbours start to touch as they rotate. Widen startAngle and endAngle to buy the room back.

The bottom of the arc is masked with a gradient, so the cards that run off the bottom edge dissolve rather than ending on a straight cut. It is on the arc alone — the copy underneath is never faded — and it is switched off in the narrow layout, where nothing is cut off at the bottom to begin with.

The height of the section comes from the arc, not the copy: it is the radius plus half a card plus a margin. Long copy pushes past that and the section grows; the pivot stays pinned to the bottom edge, so the arc travels with it.

Below 640px of section width the arc moves to the top of the section and the copy runs underneath it, with the radius widened so the ends swing off the sides rather than into the text. The feature row stacks into one column there, with rules between the items instead of beside them.