Standards

    Dog Spotlight pattern

    Highlight a curated set of dogs — e.g. longest-waiting residents — in a 4-across grid, each linking out to their listing.

    Example

    dogs accepts LocalAdoptableManifestItem[] — the same source-agnostic shape used by the local-manifest adoptable-pets loader, so hand-curated data and a future automated pull (GetBuddy, Petfinder, local manifest) share one type.

    Meet Juniper

    Juniper

    Labrador Retriever, Mixed Breed

    2 years old • Female

    Meet Juniper
    Meet Buster

    Buster

    Boxer, Mixed Breed

    4 years old • Male

    Meet Buster
    Meet Willow

    Willow

    Border Collie, Mixed Breed

    8 months old • Female

    Meet Willow
    Meet Atlas

    Atlas

    Great Pyrenees, Mixed Breed

    3 years old • Male

    Meet Atlas

    Same dogs, a different presentation

    The exact same four dogs from the example above, passed through the same component — only the optional `title`/`description`/`labels.ctaPrefix` props change, to show the data itself is presentation-agnostic.

    Ready for their forever home

    These four have been waiting the longest — give one of them a second look.

    Meet Juniper

    Juniper

    Labrador Retriever, Mixed Breed

    2 years old • Female

    Adopt Juniper
    Meet Buster

    Buster

    Boxer, Mixed Breed

    4 years old • Male

    Adopt Buster
    Meet Willow

    Willow

    Border Collie, Mixed Breed

    8 months old • Female

    Adopt Willow
    Meet Atlas

    Atlas

    Great Pyrenees, Mixed Breed

    3 years old • Male

    Adopt Atlas

    Without a detailsUrl

    A dog without a detailsUrl still renders its card (photo, name, breed, age • gender) but with no CTA button — there is nothing to link to yet.

    Meet Juniper

    Juniper

    Labrador Retriever, Mixed Breed

    2 years old • Female

    Standard

    - dogs is LocalAdoptableManifestItem[] (from adoptable-local-manifest.ts) — the same manifest shape used elsewhere in the ecosystem, so this data can start as a hand-curated array and later be swapped for an automated GetBuddy/Petfinder/local-manifest pull without changing the component.

    - Selection of which dogs to feature is entirely a call-site concern — pass in exactly the curated list, in the order you want it shown. There is no built-in sort/filter.

    - Grid is fixed at up to 4 across (`grid-cols-1 sm:grid-cols-2 lg:grid-cols-4`) — this component's whole purpose is the 4-card spotlight row, not a general-purpose gallery, so there is deliberately no `columns` prop.

    - Age • gender line is computed via `resolvePetAgeLabel()` from `lib/pet-age.ts` (never hand-rolled) using each item's `age`/`birthDate`.

    - The CTA button (default "Meet {Name}", via `labels.ctaPrefix`) renders only when `detailsUrl` is present — a dog without one still renders its card, just without a button. `ctaPrefix` is a plain word/phrase (e.g. "Meet", "Adopt"), never a {{token}}-style template string, so it's safe to pass straight through i18next's `t()` without colliding with its own interpolation syntax.

    - If `dogs` is empty, the component renders nothing — no empty-state placeholder.

    - Distinct from `AdoptablePetsSection` (the full adoptable-pets listing shell with Petfinder/Adopt-a-Pet/GetBuddy/local-manifest provider modes) — this is a small, separate curated highlight, not a listing provider.

    - Shared type: `LocalAdoptableManifestItem` in `adoptable-local-manifest.ts`

    - Component: `template/src/components/patterns/DogSpotlightSection.tsx`