← All components

Content · 8 of 13

Review

The attributed testimonial. It has no background of its own — only a 32px backdrop-filter — so it is the one component that cannot be judged on a plain surface.

Vue island src/components/common/Review.vue rendered live from compiled/Review.js Strapi

Props

PropTypeNotes
item *TestimonialReads photo.url, photo.name, name, position, review, linkedinurl, verification.
classNamestringInterpolated with no fallback — see findings.

Stories

Shown over partnership-background.svg, the ground it is built for. The blur is what separates the card from the art behind it.

Full photo + linkedinurl + verification Verification row is --color-action — see findings. The LinkedIn icon renders because linkedinurl='#!' passes the length > 1 guard (also see findings).
Minimal no photo · no linkedinurl · no verification Photo is hidden by a literal filename check: v-if="item.photo.name !== 'no-image.svg'". This story also omits className — inspect the card's class attribute and the literal string undefined is in it (see findings).

Findings

A sentinel filename controls rendering. The avatar is gated on item.photo.name !== 'no-image.svg'. The contract between CMS and component is a magic string: rename the placeholder asset in Strapi and every testimonial sprouts a broken avatar. There is also no guard on photo itself, so a testimonial with no photo relation throws on photo.name rather than falling back.

linkedinurl.length > 1 is a truthiness test in disguise. It guards against the empty string and a single character, not against an invalid URL. Any one-character-plus value renders a live external link. The same expression throws if linkedinurl is null rather than empty.

The verification row fails contrast. text-action on the site's #0A0A0B ground is 2.94:1, below the 4.5:1 floor for text this size (it was 3.03:1 against the pre-redesign #050505 — the rebuild nudged it further down). It is also the trust signal on a testimonial, so it is load-bearing copy. --color-hovered (≈8.4:1) is the in-palette fix. Same shape as DESIGN.md §10.5.

className has no fallback. The template interpolates ${className} directly, unlike ArticlePreview's ${className ?? ''}. Omitting the prop puts the literal string undefined into the class list. Harmless as a class name, but it ships in the markup.

Judge it on art, never on flat color. With no background of its own, previewing this card on #0A0A0B makes the blur invisible and the design look unfinished. That is a preview error, not a component defect.