Open demo

CSS code

HTML
<section class="qb"><span class="lbl">Quote bubbles with the avatar below</span>
<div class="qb-grid">
  <figure class="qb-fig">
    <blockquote class="qb-quote qb-down"><p>We moved our whole booking flow over in a weekend. No-shows dropped from one in eight to one in twenty.</p></blockquote>
    <figcaption class="qb-person"><img src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?auto=format&fit=crop&w=160&h=160&q=70" width="48" height="48" alt=""><span><strong>Chloe Bennett</strong><span>Owner, Fern & Fade Barbers</span></span></figcaption>
  </figure>
  <figure class="qb-fig">
    <blockquote class="qb-quote qb-down"><p>The reminders go out in the client's own language. That alone saved my front desk an hour a day.</p></blockquote>
    <figcaption class="qb-person"><img src="https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&w=160&h=160&q=70" width="48" height="48" alt=""><span><strong>Rafael Mendoza</strong><span>Clinic manager, Brightside Physio</span></span></figcaption>
  </figure>
  <figure class="qb-fig">
    <blockquote class="qb-quote qb-down"><p>Setup took twenty minutes, and support answered my one question before I'd finished my coffee.</p></blockquote>
    <figcaption class="qb-person"><img src="https://images.unsplash.com/photo-1438761681033-6461ffad8d80?auto=format&fit=crop&w=160&h=160&q=70" width="48" height="48" alt=""><span><strong>Amara Okafor</strong><span>Founder, Studio Lume Yoga</span></span></figcaption>
  </figure>
</div></section>

<section class="qb"><span class="lbl">Side bubble with a quote mark and rating</span>
<figure class="qb-fig qb-side">
  <figcaption class="qb-person"><img src="https://images.unsplash.com/photo-1500648767791-00dcc994a43e?auto=format&fit=crop&w=200&h=200&q=70" width="84" height="84" alt=""><span><strong>Jonas Weber</strong><span>Head chef, Kamin</span></span></figcaption>
  <div>
    <p class="qb-stars"><svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="m10 1.5 2.6 5.4 5.9.8-4.3 4.1 1 5.8L10 14.8l-5.2 2.8 1-5.8L1.5 7.7l5.9-.8z"/></svg><svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="m10 1.5 2.6 5.4 5.9.8-4.3 4.1 1 5.8L10 14.8l-5.2 2.8 1-5.8L1.5 7.7l5.9-.8z"/></svg><svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="m10 1.5 2.6 5.4 5.9.8-4.3 4.1 1 5.8L10 14.8l-5.2 2.8 1-5.8L1.5 7.7l5.9-.8z"/></svg><svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="m10 1.5 2.6 5.4 5.9.8-4.3 4.1 1 5.8L10 14.8l-5.2 2.8 1-5.8L1.5 7.7l5.9-.8z"/></svg><svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="m10 1.5 2.6 5.4 5.9.8-4.3 4.1 1 5.8L10 14.8l-5.2 2.8 1-5.8L1.5 7.7l5.9-.8z"/></svg><span>Rated 5 out of 5</span></p>
    <blockquote class="qb-quote qb-line"><p>Friday covers used to be a guessing game. Now I can see deposits, allergies and the big tables before I write the prep list.</p></blockquote>
    
  </div>
</figure></section>

<section class="qb"><span class="lbl">Press quote with a cited source</span>
<figure class="qb-fig qb-press">
  <blockquote class="qb-quote qb-tint" cite="https://example.com/smallbiz-weekly/booking-tools-2026"><p>The rare booking tool that small teams set up themselves and keep using a year later.</p></blockquote>
  <figcaption class="qb-person"><span class="qb-logo" aria-hidden="true">SW</span><span><cite>Small Business Weekly</cite>, booking tools review, March 2026<br><a href="#">Read the full review</a></span></figcaption>
</figure></section>
CSS
/* Testimonial quote bubbles: a <figure> holds the <blockquote> (the bubble) and a <figcaption> with the person.
   The tail points from the quote to the face, so readers see who is speaking. */
.qb{--qb-bg:#fff;--qb-ink:#221d17;--qb-muted:#5f574c;--qb-accent:#b4410e;--qb-line:#e6ded2;--qb-t:14px}
.qb-fig{display:flex;flex-direction:column;margin:0}
.qb-quote{position:relative;margin:0;padding:22px 24px;border-radius:18px;background:var(--qb-bg);color:var(--qb-ink);
  box-shadow:0 1px 2px rgba(34,29,23,.06),0 16px 32px -20px rgba(34,29,23,.35);font-size:.98rem;line-height:1.55}
.qb-quote p{margin:0}
.qb-person{display:flex;align-items:center;gap:12px;margin-top:22px;padding-left:12px;font-size:.88rem;line-height:1.3}
.qb-person img{flex:none;width:48px;height:48px;border-radius:50%;object-fit:cover}
.qb-person strong{display:block;font-size:.95rem}
.qb-person strong+span{display:block;color:var(--qb-muted)}

/* 1. Tail under the quote, aimed at the avatar */
.qb-down::after{content:"";position:absolute;top:100%;left:30px;border:var(--qb-t) solid transparent;border-top-color:var(--qb-bg);border-bottom-width:0;border-left-width:0}
.qb-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,280px),1fr));gap:36px 28px;align-items:start}

/* 2. Avatar beside an outlined bubble, a large decorative quote mark and a written-out rating */
.qb-side{display:grid;grid-template-columns:auto 1fr;gap:12px 30px;align-items:center;max-width:760px}
.qb-side .qb-person{flex-direction:column;align-items:center;gap:8px;margin:0;padding:0;text-align:center}
.qb-side .qb-person img{width:84px;height:84px}
.qb-line{border:1.5px solid var(--qb-line);box-shadow:none;padding:28px 30px 24px 56px;font-size:1.05rem}
.qb-line::before{content:"\201C" / "";position:absolute;top:6px;left:16px;font:700 4rem/1 Georgia,"Times New Roman",serif;color:var(--qb-accent)}
.qb-line::after{content:"";position:absolute;top:50%;left:0;width:18px;height:18px;border:solid var(--qb-line);border-width:0 0 1.5px 1.5px;background:var(--qb-bg);translate:-50% -50%;rotate:45deg}
.qb-stars{display:flex;align-items:center;gap:2px;margin:0 0 12px;color:var(--qb-accent);font-size:.82rem;font-weight:600}
.qb-stars svg{width:16px;height:16px}
.qb-stars span{margin-left:8px;color:var(--qb-muted)}
@media (max-width:560px){.qb-side{grid-template-columns:1fr}.qb-side .qb-person{flex-direction:row;justify-content:flex-start;text-align:left;order:2}
  .qb-side .qb-person img{width:56px;height:56px}.qb-line{padding:26px 22px 22px 58px}
  .qb-line::after{top:100%;left:40px;border-width:0 1.5px 1.5px 0}}

/* 3. Press quote: serif type on a tinted bubble with a corner tail, source in <cite> */
.qb-press{max-width:640px}
.qb-tint{--qb-bg:#2a1f14;--qb-ink:#fbf3e6;padding:30px 32px;border-radius:22px 22px 22px 0;font:400 1.35rem/1.45 Georgia,"Times New Roman",serif}
.qb-tint::after{content:"";position:absolute;top:100%;left:0;border:solid transparent;border-width:20px 26px 0 0;border-top-color:var(--qb-bg)}
.qb-press .qb-person{padding-left:0;margin-top:30px}
.qb-press cite{font-style:normal;font-weight:700}
.qb-press a{color:var(--qb-accent);font-weight:600;text-underline-offset:3px}
.qb-press a:focus-visible{outline:2px solid var(--qb-accent);outline-offset:2px;border-radius:2px}
.qb-logo{display:grid;place-items:center;flex:none;width:48px;height:48px;border-radius:12px;background:#efe6d8;color:#2a1f14;font:700 1.1rem/1 Georgia,serif}

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<section class="qb"><span class="lbl">Quote bubbles with the avatar below</span>
<div class="row g-4 gy-5 align-items-start">
  <div class="col-md-4"><figure class="qb-fig d-flex flex-column mb-0">
    <blockquote class="blockquote mb-0 qb-quote qb-down"><p>We moved our whole booking flow over in a weekend. No-shows dropped from one in eight to one in twenty.</p></blockquote>
    <figcaption class="qb-person d-flex align-items-center gap-3"><img src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?auto=format&fit=crop&w=160&h=160&q=70" width="48" height="48" class="rounded-circle" alt=""><span><strong>Chloe Bennett</strong><span>Owner, Fern & Fade Barbers</span></span></figcaption>
  </figure></div>
  <div class="col-md-4"><figure class="qb-fig d-flex flex-column mb-0">
    <blockquote class="blockquote mb-0 qb-quote qb-down"><p>The reminders go out in the client's own language. That alone saved my front desk an hour a day.</p></blockquote>
    <figcaption class="qb-person d-flex align-items-center gap-3"><img src="https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&w=160&h=160&q=70" width="48" height="48" class="rounded-circle" alt=""><span><strong>Rafael Mendoza</strong><span>Clinic manager, Brightside Physio</span></span></figcaption>
  </figure></div>
  <div class="col-md-4"><figure class="qb-fig d-flex flex-column mb-0">
    <blockquote class="blockquote mb-0 qb-quote qb-down"><p>Setup took twenty minutes, and support answered my one question before I'd finished my coffee.</p></blockquote>
    <figcaption class="qb-person d-flex align-items-center gap-3"><img src="https://images.unsplash.com/photo-1438761681033-6461ffad8d80?auto=format&fit=crop&w=160&h=160&q=70" width="48" height="48" class="rounded-circle" alt=""><span><strong>Amara Okafor</strong><span>Founder, Studio Lume Yoga</span></span></figcaption>
  </figure>
</div></section>

<section class="qb"><span class="lbl">Side bubble with a quote mark and rating</span>
<figure class="qb-fig qb-side">
  <figcaption class="qb-person d-flex align-items-center gap-3"><img src="https://images.unsplash.com/photo-1500648767791-00dcc994a43e?auto=format&fit=crop&w=200&h=200&q=70" width="84" height="84" class="rounded-circle" alt=""><span><strong>Jonas Weber</strong><span>Head chef, Kamin</span></span></figcaption>
  <div>
    <p class="qb-stars d-flex align-items-center gap-1 fw-semibold"><svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="m10 1.5 2.6 5.4 5.9.8-4.3 4.1 1 5.8L10 14.8l-5.2 2.8 1-5.8L1.5 7.7l5.9-.8z"/></svg><svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="m10 1.5 2.6 5.4 5.9.8-4.3 4.1 1 5.8L10 14.8l-5.2 2.8 1-5.8L1.5 7.7l5.9-.8z"/></svg><svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="m10 1.5 2.6 5.4 5.9.8-4.3 4.1 1 5.8L10 14.8l-5.2 2.8 1-5.8L1.5 7.7l5.9-.8z"/></svg><svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="m10 1.5 2.6 5.4 5.9.8-4.3 4.1 1 5.8L10 14.8l-5.2 2.8 1-5.8L1.5 7.7l5.9-.8z"/></svg><svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="m10 1.5 2.6 5.4 5.9.8-4.3 4.1 1 5.8L10 14.8l-5.2 2.8 1-5.8L1.5 7.7l5.9-.8z"/></svg><span>Rated 5 out of 5</span></p>
    <blockquote class="blockquote mb-0 qb-quote qb-line"><p>Friday covers used to be a guessing game. Now I can see deposits, allergies and the big tables before I write the prep list.</p></blockquote>
    
  </div>
</figure></section>

<section class="qb"><span class="lbl">Press quote with a cited source</span>
<figure class="qb-fig qb-press">
  <blockquote class="blockquote mb-0 qb-quote qb-tint" cite="https://example.com/smallbiz-weekly/booking-tools-2026"><p>The rare booking tool that small teams set up themselves and keep using a year later.</p></blockquote>
  <figcaption class="qb-person d-flex align-items-center gap-3"><span class="qb-logo" aria-hidden="true">SW</span><span><cite>Small Business Weekly</cite>, booking tools review, March 2026<br><a class="link-offset-1" href="#">Read the full review</a></span></figcaption>
</figure></section>
CSS
/* Testimonial quote bubbles on Bootstrap (.row, .blockquote, .rounded-circle and flex utilities): a <figure> holds the <blockquote> (the bubble) and a <figcaption> with the person.
   The tail points from the quote to the face, so readers see who is speaking. */
.qb{--qb-bg:#fff;--qb-ink:#221d17;--qb-muted:#5f574c;--qb-accent:#b4410e;--qb-line:#e6ded2;--qb-t:14px}
.qb-fig{display:flex;flex-direction:column;margin:0}
.qb-quote{position:relative;margin:0;padding:22px 24px;border-radius:18px;background:var(--qb-bg);color:var(--qb-ink);
  box-shadow:0 1px 2px rgba(34,29,23,.06),0 16px 32px -20px rgba(34,29,23,.35);font-size:.98rem;line-height:1.55}
.qb-quote p{margin:0}
.qb-person{display:flex;align-items:center;gap:12px;margin-top:22px;padding-left:12px;font-size:.88rem;line-height:1.3}
.qb-person img{flex:none;width:48px;height:48px;object-fit:cover}
.qb-person strong{display:block;font-size:.95rem}
.qb-person strong+span{display:block;color:var(--qb-muted)}

/* 1. Tail under the quote, aimed at the avatar */
.qb-down::after{content:"";position:absolute;top:100%;left:30px;border:var(--qb-t) solid transparent;border-top-color:var(--qb-bg);border-bottom-width:0;border-left-width:0}
.qb-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,280px),1fr));gap:36px 28px;align-items:start}

/* 2. Avatar beside an outlined bubble, a large decorative quote mark and a written-out rating */
.qb-side{display:grid;grid-template-columns:auto 1fr;gap:12px 30px;align-items:center;max-width:760px}
.qb-side .qb-person{flex-direction:column;align-items:center;gap:8px;margin:0;padding:0;text-align:center}
.qb-side .qb-person img{width:84px;height:84px}
.qb-line{border:1.5px solid var(--qb-line);box-shadow:none;padding:28px 30px 24px 56px;font-size:1.05rem}
.qb-line::before{content:"\201C" / "";position:absolute;top:6px;left:16px;font:700 4rem/1 Georgia,"Times New Roman",serif;color:var(--qb-accent)}
.qb-line::after{content:"";position:absolute;top:50%;left:0;width:18px;height:18px;border:solid var(--qb-line);border-width:0 0 1.5px 1.5px;background:var(--qb-bg);translate:-50% -50%;rotate:45deg}
.qb-stars{display:flex;align-items:center;gap:2px;margin:0 0 12px;color:var(--qb-accent);font-size:.82rem;font-weight:600}
.qb-stars svg{width:16px;height:16px}
.qb-stars span{margin-left:8px;color:var(--qb-muted)}
@media (max-width:560px){.qb-side{grid-template-columns:1fr}.qb-side .qb-person{flex-direction:row;justify-content:flex-start;text-align:left;order:2}
  .qb-side .qb-person img{width:56px;height:56px}.qb-line{padding:26px 22px 22px 58px}
  .qb-line::after{top:100%;left:40px;border-width:0 1.5px 1.5px 0}}

/* 3. Press quote: serif type on a tinted bubble with a corner tail, source in <cite> */
.qb-press{max-width:640px}
.qb-tint{--qb-bg:#2a1f14;--qb-ink:#fbf3e6;padding:30px 32px;border-radius:22px 22px 22px 0;font:400 1.35rem/1.45 Georgia,"Times New Roman",serif}
.qb-tint::after{content:"";position:absolute;top:100%;left:0;border:solid transparent;border-width:20px 26px 0 0;border-top-color:var(--qb-bg)}
.qb-press .qb-person{padding-left:0;margin-top:30px}
.qb-press cite{font-style:normal;font-weight:700}
.qb-press a{color:var(--qb-accent);font-weight:600;text-underline-offset:3px}
.qb-press a:focus-visible{outline:2px solid var(--qb-accent);outline-offset:2px;border-radius:2px}
.qb-logo{display:grid;place-items:center;flex:none;width:48px;height:48px;border-radius:12px;background:#efe6d8;color:#2a1f14;font:700 1.1rem/1 Georgia,serif}

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<section><span class="mb-[18px] block text-[.72rem] tracking-[.12em] text-qb-muted uppercase">Quote bubbles with the avatar below</span>
<div class="grid grid-cols-[repeat(auto-fit,minmax(min(100%,280px),1fr))] items-start gap-x-7 gap-y-9">
  <figure class="m-0 flex flex-col">
    <blockquote class="qb-down relative m-0 rounded-[18px] bg-white px-6 py-[22px] text-[.98rem] leading-[1.55] text-qb-ink shadow-[0_1px_2px_rgba(34,29,23,.06),0_16px_32px_-20px_rgba(34,29,23,.35)]"><p>We moved our whole booking flow over in a weekend. No-shows dropped from one in eight to one in twenty.</p></blockquote>
    <figcaption class="mt-[22px] flex items-center gap-3 pl-3 text-[.88rem] leading-[1.3]"><img class="size-12 flex-none rounded-full object-cover" src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?auto=format&fit=crop&w=160&h=160&q=70" width="48" height="48" alt=""><span><strong class="block text-[.95rem]">Chloe Bennett</strong><span class="block text-qb-muted">Owner, Fern & Fade Barbers</span></span></figcaption>
  </figure>
  <figure class="m-0 flex flex-col">
    <blockquote class="qb-down relative m-0 rounded-[18px] bg-white px-6 py-[22px] text-[.98rem] leading-[1.55] text-qb-ink shadow-[0_1px_2px_rgba(34,29,23,.06),0_16px_32px_-20px_rgba(34,29,23,.35)]"><p>The reminders go out in the client's own language. That alone saved my front desk an hour a day.</p></blockquote>
    <figcaption class="mt-[22px] flex items-center gap-3 pl-3 text-[.88rem] leading-[1.3]"><img class="size-12 flex-none rounded-full object-cover" src="https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&w=160&h=160&q=70" width="48" height="48" alt=""><span><strong class="block text-[.95rem]">Rafael Mendoza</strong><span class="block text-qb-muted">Clinic manager, Brightside Physio</span></span></figcaption>
  </figure>
  <figure class="m-0 flex flex-col">
    <blockquote class="qb-down relative m-0 rounded-[18px] bg-white px-6 py-[22px] text-[.98rem] leading-[1.55] text-qb-ink shadow-[0_1px_2px_rgba(34,29,23,.06),0_16px_32px_-20px_rgba(34,29,23,.35)]"><p>Setup took twenty minutes, and support answered my one question before I'd finished my coffee.</p></blockquote>
    <figcaption class="mt-[22px] flex items-center gap-3 pl-3 text-[.88rem] leading-[1.3]"><img class="size-12 flex-none rounded-full object-cover" src="https://images.unsplash.com/photo-1438761681033-6461ffad8d80?auto=format&fit=crop&w=160&h=160&q=70" width="48" height="48" alt=""><span><strong class="block text-[.95rem]">Amara Okafor</strong><span class="block text-qb-muted">Founder, Studio Lume Yoga</span></span></figcaption>
  </figure>
</div></section>

<section><span class="mb-[18px] block text-[.72rem] tracking-[.12em] text-qb-muted uppercase">Side bubble with a quote mark and rating</span>
<figure class="m-0 grid max-w-[760px] grid-cols-[auto_1fr] items-center gap-x-[30px] gap-y-3 max-[559px]:grid-cols-1">
  <figcaption class="m-0 flex flex-col items-center gap-2 text-center text-[.88rem] leading-[1.3] max-[559px]:order-2 max-[559px]:flex-row max-[559px]:text-left"><img class="size-[84px] flex-none rounded-full object-cover max-[559px]:size-14" src="https://images.unsplash.com/photo-1500648767791-00dcc994a43e?auto=format&fit=crop&w=200&h=200&q=70" width="84" height="84" alt=""><span><strong class="block text-[.95rem]">Jonas Weber</strong><span class="block text-qb-muted">Head chef, Kamin</span></span></figcaption>
  <div>
    <p class="mb-3 flex items-center gap-0.5 text-[.82rem] font-semibold text-qb-accent"><svg class="size-4" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="m10 1.5 2.6 5.4 5.9.8-4.3 4.1 1 5.8L10 14.8l-5.2 2.8 1-5.8L1.5 7.7l5.9-.8z"/></svg><svg class="size-4" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="m10 1.5 2.6 5.4 5.9.8-4.3 4.1 1 5.8L10 14.8l-5.2 2.8 1-5.8L1.5 7.7l5.9-.8z"/></svg><svg class="size-4" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="m10 1.5 2.6 5.4 5.9.8-4.3 4.1 1 5.8L10 14.8l-5.2 2.8 1-5.8L1.5 7.7l5.9-.8z"/></svg><svg class="size-4" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="m10 1.5 2.6 5.4 5.9.8-4.3 4.1 1 5.8L10 14.8l-5.2 2.8 1-5.8L1.5 7.7l5.9-.8z"/></svg><svg class="size-4" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="m10 1.5 2.6 5.4 5.9.8-4.3 4.1 1 5.8L10 14.8l-5.2 2.8 1-5.8L1.5 7.7l5.9-.8z"/></svg><span class="ml-2 text-qb-muted">Rated 5 out of 5</span></p>
    <blockquote class="qb-side relative m-0 rounded-[18px] border-[1.5px] border-qb-line bg-white pt-7 pr-[30px] pb-6 pl-14 text-[1.05rem] leading-[1.55] text-qb-ink max-[559px]:pt-[26px] max-[559px]:pr-[22px] max-[559px]:pb-[22px] max-[559px]:pl-[58px]"><span class="absolute top-1.5 left-4 font-[Georgia,'Times_New_Roman',serif] text-[4rem] leading-none font-bold text-qb-accent" aria-hidden="true">“</span><p>Friday covers used to be a guessing game. Now I can see deposits, allergies and the big tables before I write the prep list.</p></blockquote>
  </div>
</figure></section>

<section><span class="mb-[18px] block text-[.72rem] tracking-[.12em] text-qb-muted uppercase">Press quote with a cited source</span>
<figure class="m-0 flex max-w-[640px] flex-col">
  <blockquote class="qb-corner relative m-0 rounded-[22px_22px_22px_0] bg-[#2a1f14] px-8 py-[30px] font-[Georgia,'Times_New_Roman',serif] text-[1.35rem] leading-[1.45] text-[#fbf3e6] shadow-[0_1px_2px_rgba(34,29,23,.06),0_16px_32px_-20px_rgba(34,29,23,.35)]" cite="https://example.com/smallbiz-weekly/booking-tools-2026"><p>The rare booking tool that small teams set up themselves and keep using a year later.</p></blockquote>
  <figcaption class="mt-[30px] flex items-center gap-3 text-[.88rem] leading-[1.3]"><span class="grid size-12 flex-none place-items-center rounded-xl bg-[#efe6d8] font-[Georgia,serif] text-[1.1rem] leading-none font-bold text-[#2a1f14]" aria-hidden="true">SW</span><span><cite class="font-bold not-italic">Small Business Weekly</cite>, booking tools review, March 2026<br><a class="font-semibold text-qb-accent underline underline-offset-3 focus-visible:rounded-xs focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-qb-accent" href="#">Read the full review</a></span></figcaption>
</figure></section>
CSS
@theme {
  --color-qb-ink:#221d17; --color-qb-muted:#5f574c; --color-qb-accent:#b4410e; --color-qb-line:#e6ded2;
}
/* Utilities draw the bubbles; the tails are repeated pseudo-elements, so they live here. */
.qb-down::after{content:"";position:absolute;top:100%;left:30px;border:14px solid transparent;border-top-color:#fff;border-bottom-width:0;border-left-width:0}
.qb-side::after{content:"";position:absolute;top:50%;left:0;width:18px;height:18px;border:solid var(--color-qb-line);border-width:0 0 1.5px 1.5px;background:#fff;translate:-50% -50%;rotate:45deg}
@media (max-width:559px){.qb-side::after{top:100%;left:40px;border-width:0 1.5px 1.5px 0}}
.qb-corner::after{content:"";position:absolute;top:100%;left:0;border:solid transparent;border-width:20px 26px 0 0;border-top-color:#2a1f14}

About this set

Testimonials drawn as speech bubbles, so the tail shows who is speaking. Each one is a figure: the bubble is a blockquote and the person is a figcaption. Quote bubbles with the avatar below is a three-column grid of short customer quotes, each with a tail pointing down at a round photo, a name and a role. Side bubble with a quote mark and rating places a large photo beside an outlined bubble with a rotated-square tail that shares the outline, a decorative opening quote mark and a five-star rating written out as Rated 5 out of 5. On narrow screens the person moves under the bubble and the tail turns to point down at them. Press quote with a cited source sets a magazine line in Georgia on a dark bubble with a corner tail, puts the publication in a cite element, adds the source URL to the blockquote’s cite attribute and links to the full review. Use the grid for a row of customer quotes, the side bubble for one featured quote, and the press quote for coverage from a named source.

What’s included

  • figure, blockquote and figcaption markup for each testimonial
  • Tails that point from the quote to the person
  • Outlined bubble whose tail moves below on narrow screens
  • Star rating written out as text
  • Press quote with a cite element and cite attribute

Accessibility

Quotes are blockquote elements inside figures, so the quote and the person are announced together. Avatar photos have empty alt text because the name sits next to them, the stars are hidden and the rating is written as text, and the large quote mark is decorative. The review link shows a 2px focus outline and all text reaches at least 4.5:1.

Customise it

Change --qb-bg, --qb-accent, --qb-line and --qb-t on .qb for bubble colour, accent, outline and tail size; the press bubble overrides --qb-bg in .qb-tint. In Tailwind edit the --color-qb-* theme colours; Bootstrap uses the same variables with .blockquote, .rounded-circle and .row.