Testimonials
Attributed quotes in a wall, the words, the person who said them, and the picture that may stand in for them.
A testimonials band is the evidence between the features and the price: a few short quotes, each credited to the person who said it. It is the band where a page stops describing the product and lets somebody else do it.
Reach for it when the quotes are specific and attributed, a named person, a role, a company. A
wall of anonymous praise is worse than no wall at all, which is why name is the one field the
type requires.
Usage
import { Testimonials } from "@asheeui/web";
<Testimonials
items={[
{
quote: "We cut campaign setup from hours to minutes.",
name: "Ama Boateng",
role: "Head of growth, Kora Retail",
},
]}
/>
Each item is a value: a quote, a name, an optional role and an optional picture. The heading
block, the spacing and the column options are the ones every marketing band takes, and children
renders below the quotes. An item may also state an id, used as its key when a builder can
reorder the wall.
The quote and its attribution
quote is the only content in the card, and name is printed under it. role is optional, most
founders do not need one, and its line is drawn only when it is given, so an attribution without a
role is a complete one rather than a gap.
There is no anonymous variant: the band always draws the attribution, and a quote that arrives without a name (a builder field left empty, a payload that skipped it) renders its words over an empty line, beside an avatar with no initials and no label. A reader then hears a quotation with no author, which is the one thing this band exists to prevent. If you have the words but not the person, they do not belong here.
Length is what goes wrong next. A row of cards shares one height, so the longest quote sets it and its neighbours keep the slack: a four-line quote makes a one-line quote beside it look like a caption. Two sentences is a wall; the quote that is one sentence and one number is the one that gets read.
Pictures and substitutions
Every quote can have a picture, and none of them has to. avatarSrc is the URL handed to the
framework's Avatar, which derives the initials of name and shows them when there is no picture
at all, or when the picture fails to load. A new avatarSrc is a new picture, so a wall that swaps
an item tries again rather than keeping the fallback the previous one earned.
avatarComponent and avatarComponentProps are the substitution seam. avatarComponent is the
framework's image component itself, the export from next/image, expo-image or whatever the
product already loads pictures with, and avatarComponentProps is what that component needs. The
band hands it a filled element: fill and sizes are supplied for it unless those props state
width, height or fill, and the props you pass win over the ones the framework supplies.
The substitution reaches the picture and nothing else. An item with no avatarSrc still draws its
initials whatever avatarComponent names, so one band mixes pictures and initials without a second
code path, which is what makes this seam worth using for a CDN with an allow-list, or for a
framework's optimised image, rather than a change at every call site.
Props
The nine options are registered under components.testimonials as columns: 1, columnsMd: 2,
columnsLg: 3, gap: "lg", spacing: "lg", background: "none", align: "center",
containerSize: "lg" and contained: true, deliberately the same values the feature grid
registers, so two adjacent bands line up without either of them stating anything. Each resolves
from the instance, then that section, then the registered value, and each of the three counts
resolves on its own: columns={2} alone still gives two at md and three at lg.
Two values resolve from outside this band. Each quote is a bordered Card at md density, so
its radius follows the application's defaultRadius, and the avatar's fallback circle takes its
colour from defaultColor and its radius from defaultRadius. A product that themes those two
values themes this band without touching it. items, children, as and the heading, its
content, its level (titleAs) and its size (headingSize), are instance-only, because the
quotes and the page's outline belong to the page rather than to the design.
Accessibility
titlerenders a level-two heading by default, and each quote is afigurewith ablockquoteinside it and afigcaptionfor the attribution, so a reader hears a quoted passage with its author attached rather than a paragraph that happens to sit in quotation marks.titleAsstates another level,h1for the wall whose heading is the page's title,h3for one nested under a section heading, andheadingSizechanges the treatment without touching the level.- The quotes are one list, so a reader hears how many there are before the first one and can move
between them. The
<section>the band draws is named by that heading througharia-labelledby, so it is a region a reader can jump to; a band with notitlehas nothing to be named by and stays unnamed, which is whenaria-labelis worth passing. - The avatar is decorative: it is passed an empty
alt, so assistive technology skips it, and the caption's name is what a reader hears once. The initials fallback is hidden for the same reason, the caption already carries the name. - Nothing the band draws is focusable, quotes are words, so Tab passes over the wall and the page's only stops remain the ones its other bands supply.
The heading block, the data-not-markup decision and the one-h1 rule are shared by every band,
see Marketing sections.