25 CSS Blockquotes02 / 25
Tailwind CSS Blockquote Component
The Tailwind UI testimonial pattern — dark slate card, ring-1 border, avatar with an indigo ring, quote in font-semibold — rebuilt twice: once as the exact utility-class markup Tailwind users search for, and once as the plain-CSS translation that runs with zero build step (that's what renders here). Every utility is annotated with its CSS equivalent, so the demo doubles as a Tailwind-to-vanilla dictionary: ring-1 ring-white/10 is a box-shadow, not a border; divide-x is a sibling selector; the avatar ring is two stacked shadows.
Published
The code
<section class="bq-02" aria-label="Tailwind style blockquote component demo">
<div class="bq-02__stage">
<figure class="bq-02__card">
<svg class="bq-02__logo" viewBox="0 0 32 32" width="30" height="30" aria-hidden="true"><path d="M16 4l12 7v10l-12 7L4 21V11z" fill="none" stroke="currentColor" stroke-width="2.4"/><circle cx="16" cy="16" r="4.2" fill="currentColor"/></svg>
<blockquote class="bq-02__text-lg">
<p>“Utility classes made our design system reviewable. Every visual decision is right there in the diff — no hunting through stylesheets to find who set that margin.”</p>
</blockquote>
<figcaption class="bq-02__row">
<img class="bq-02__avatar" src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?q=80&w=160&auto=format&fit=crop" alt="" width="40" height="40" loading="lazy">
<div class="bq-02__who">
<div class="bq-02__name">Judith Black</div>
<div class="bq-02__role">CEO of Workcation</div>
</div>
<span class="bq-02__x" aria-hidden="true"></span>
<div class="bq-02__meta">ring-1 · ring-white/10</div>
</figcaption>
</figure>
<p class="bq-02__chip" aria-hidden="true">Tailwind pattern → plain CSS · ring = box-shadow · container query re-stack</p>
</div>
</section><section class="bq-02" aria-label="Tailwind style blockquote component demo">
<div class="bq-02__stage">
<figure class="bq-02__card">
<svg class="bq-02__logo" viewBox="0 0 32 32" width="30" height="30" aria-hidden="true"><path d="M16 4l12 7v10l-12 7L4 21V11z" fill="none" stroke="currentColor" stroke-width="2.4"/><circle cx="16" cy="16" r="4.2" fill="currentColor"/></svg>
<blockquote class="bq-02__text-lg">
<p>“Utility classes made our design system reviewable. Every visual decision is right there in the diff — no hunting through stylesheets to find who set that margin.”</p>
</blockquote>
<figcaption class="bq-02__row">
<img class="bq-02__avatar" src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?q=80&w=160&auto=format&fit=crop" alt="" width="40" height="40" loading="lazy">
<div class="bq-02__who">
<div class="bq-02__name">Judith Black</div>
<div class="bq-02__role">CEO of Workcation</div>
</div>
<span class="bq-02__x" aria-hidden="true"></span>
<div class="bq-02__meta">ring-1 · ring-white/10</div>
</figcaption>
</figure>
<p class="bq-02__chip" aria-hidden="true">Tailwind pattern → plain CSS · ring = box-shadow · container query re-stack</p>
</div>
</section>.bq-02,
.bq-02 *,
.bq-02 *::before,
.bq-02 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.bq-02 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
--bg: oklch(0.14 0.015 265);
--card: oklch(0.21 0.02 265);
--ink: oklch(0.97 0.005 250);
--mut: oklch(0.67 0.02 260);
--acc: oklch(0.6 0.19 275);
font-family: 'Segoe UI',system-ui,sans-serif;
color: var(--ink);
}
.bq-02__stage {
width: 100%;
height: 100vh;
height: 100svh;
display: grid;
place-items: center;
align-content: center;
gap: 24px;
padding: clamp(20px,5vw,56px);
background: radial-gradient(90% 70% at 50% 110%,oklch(0.22 0.05 275/.6),transparent),var(--bg);
overflow-y: auto;
}
.bq-02__card {
width: min(100%,36rem);
padding: 2rem;
border-radius: 1rem;
background: var(--card);
box-shadow: 0 0 0 1px oklch(1 0 0/.1),0 22px 50px oklch(0 0 0/.42);
container-type: inline-size;
}
.bq-02__logo {
color: var(--acc);
margin-bottom: 1.25rem;
display: block;
}
.bq-02__text-lg p {
font-size: 1.125rem;
line-height: 1.65;
font-weight: 600;
letter-spacing: -.008em;
text-wrap: pretty;
}
.bq-02__row {
display: flex;
align-items: center;
gap: 1rem;
margin-top: 1.5rem;
}
.bq-02__avatar {
width: 2.5rem;
height: 2.5rem;
border-radius: 99px;
object-fit: cover;
flex: none;
background: linear-gradient(135deg,oklch(0.5 0.1 275),oklch(0.35 0.06 300));
box-shadow: 0 0 0 2px var(--acc),0 0 0 4px color-mix(in oklch,var(--acc) 30%,transparent);
}
.bq-02__name {
font-size: .9rem;
font-weight: 650;
}
.bq-02__role {
font-size: .82rem;
color: var(--mut);
margin-top: 1px;
}
.bq-02__x {
width: 1px;
height: 1.6rem;
background: oklch(1 0 0/.12);
margin-left: auto;
}
.bq-02__meta {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: .7rem;
color: var(--mut);
}
.bq-02__chip {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11.5px;
color: var(--mut);
padding: 7px 13px;
border-radius: 99px;
box-shadow: 0 0 0 1px oklch(1 0 0/.1);
}
@container (width < 420px) {
.bq-02__row {
flex-wrap: wrap;
}
.bq-02__x,
.bq-02__meta {
display: none;
}
}
@media (prefers-reduced-motion: reduce) {
.bq-02 * {
transition-duration: .01ms !important;
}
}.bq-02,
.bq-02 *,
.bq-02 *::before,
.bq-02 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.bq-02 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
--bg: oklch(0.14 0.015 265);
--card: oklch(0.21 0.02 265);
--ink: oklch(0.97 0.005 250);
--mut: oklch(0.67 0.02 260);
--acc: oklch(0.6 0.19 275);
font-family: 'Segoe UI',system-ui,sans-serif;
color: var(--ink);
}
.bq-02__stage {
width: 100%;
height: 100vh;
height: 100svh;
display: grid;
place-items: center;
align-content: center;
gap: 24px;
padding: clamp(20px,5vw,56px);
background: radial-gradient(90% 70% at 50% 110%,oklch(0.22 0.05 275/.6),transparent),var(--bg);
overflow-y: auto;
}
.bq-02__card {
width: min(100%,36rem);
padding: 2rem;
border-radius: 1rem;
background: var(--card);
box-shadow: 0 0 0 1px oklch(1 0 0/.1),0 22px 50px oklch(0 0 0/.42);
container-type: inline-size;
}
.bq-02__logo {
color: var(--acc);
margin-bottom: 1.25rem;
display: block;
}
.bq-02__text-lg p {
font-size: 1.125rem;
line-height: 1.65;
font-weight: 600;
letter-spacing: -.008em;
text-wrap: pretty;
}
.bq-02__row {
display: flex;
align-items: center;
gap: 1rem;
margin-top: 1.5rem;
}
.bq-02__avatar {
width: 2.5rem;
height: 2.5rem;
border-radius: 99px;
object-fit: cover;
flex: none;
background: linear-gradient(135deg,oklch(0.5 0.1 275),oklch(0.35 0.06 300));
box-shadow: 0 0 0 2px var(--acc),0 0 0 4px color-mix(in oklch,var(--acc) 30%,transparent);
}
.bq-02__name {
font-size: .9rem;
font-weight: 650;
}
.bq-02__role {
font-size: .82rem;
color: var(--mut);
margin-top: 1px;
}
.bq-02__x {
width: 1px;
height: 1.6rem;
background: oklch(1 0 0/.12);
margin-left: auto;
}
.bq-02__meta {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: .7rem;
color: var(--mut);
}
.bq-02__chip {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11.5px;
color: var(--mut);
padding: 7px 13px;
border-radius: 99px;
box-shadow: 0 0 0 1px oklch(1 0 0/.1);
}
@container (width < 420px) {
.bq-02__row {
flex-wrap: wrap;
}
.bq-02__x,
.bq-02__meta {
display: none;
}
}
@media (prefers-reduced-motion: reduce) {
.bq-02 * {
transition-duration: .01ms !important;
}
}Here's a working CSS Blockquote from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind CSS Blockquote Component
Source: https://codefronts.com/snippets/css-blockquotes/tailwind-css-blockquote-component/
The Tailwind UI testimonial pattern — dark slate card, ring-1 border, avatar with an indigo ring, quote in font-semibold — rebuilt twice: once as the exact utility-class markup Tailwind users search for, and once as the plain-CSS translation that runs with zero build step (that's what renders here). Every utility is annotated with its CSS equivalent, so the demo doubles as a Tailwind-to-vanilla dictionary: ring-1 ring-white/10 is a box-shadow, not a border; divide-x is a sibling selector; the avatar ring is two stacked shadows.
## HTML
```html
<section class="bq-02" aria-label="Tailwind style blockquote component demo">
<div class="bq-02__stage">
<figure class="bq-02__card">
<svg class="bq-02__logo" viewBox="0 0 32 32" width="30" height="30" aria-hidden="true"><path d="M16 4l12 7v10l-12 7L4 21V11z" fill="none" stroke="currentColor" stroke-width="2.4"/><circle cx="16" cy="16" r="4.2" fill="currentColor"/></svg>
<blockquote class="bq-02__text-lg">
<p>“Utility classes made our design system reviewable. Every visual decision is right there in the diff — no hunting through stylesheets to find who set that margin.”</p>
</blockquote>
<figcaption class="bq-02__row">
<img class="bq-02__avatar" src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?q=80&w=160&auto=format&fit=crop" alt="" width="40" height="40" loading="lazy">
<div class="bq-02__who">
<div class="bq-02__name">Judith Black</div>
<div class="bq-02__role">CEO of Workcation</div>
</div>
<span class="bq-02__x" aria-hidden="true"></span>
<div class="bq-02__meta">ring-1 · ring-white/10</div>
</figcaption>
</figure>
<p class="bq-02__chip" aria-hidden="true">Tailwind pattern → plain CSS · ring = box-shadow · container query re-stack</p>
</div>
</section>
```
## CSS
```css
.bq-02,
.bq-02 *,
.bq-02 *::before,
.bq-02 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.bq-02 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
--bg: oklch(0.14 0.015 265);
--card: oklch(0.21 0.02 265);
--ink: oklch(0.97 0.005 250);
--mut: oklch(0.67 0.02 260);
--acc: oklch(0.6 0.19 275);
font-family: 'Segoe UI',system-ui,sans-serif;
color: var(--ink);
}
.bq-02__stage {
width: 100%;
height: 100vh;
height: 100svh;
display: grid;
place-items: center;
align-content: center;
gap: 24px;
padding: clamp(20px,5vw,56px);
background: radial-gradient(90% 70% at 50% 110%,oklch(0.22 0.05 275/.6),transparent),var(--bg);
overflow-y: auto;
}
.bq-02__card {
width: min(100%,36rem);
padding: 2rem;
border-radius: 1rem;
background: var(--card);
box-shadow: 0 0 0 1px oklch(1 0 0/.1),0 22px 50px oklch(0 0 0/.42);
container-type: inline-size;
}
.bq-02__logo {
color: var(--acc);
margin-bottom: 1.25rem;
display: block;
}
.bq-02__text-lg p {
font-size: 1.125rem;
line-height: 1.65;
font-weight: 600;
letter-spacing: -.008em;
text-wrap: pretty;
}
.bq-02__row {
display: flex;
align-items: center;
gap: 1rem;
margin-top: 1.5rem;
}
.bq-02__avatar {
width: 2.5rem;
height: 2.5rem;
border-radius: 99px;
object-fit: cover;
flex: none;
background: linear-gradient(135deg,oklch(0.5 0.1 275),oklch(0.35 0.06 300));
box-shadow: 0 0 0 2px var(--acc),0 0 0 4px color-mix(in oklch,var(--acc) 30%,transparent);
}
.bq-02__name {
font-size: .9rem;
font-weight: 650;
}
.bq-02__role {
font-size: .82rem;
color: var(--mut);
margin-top: 1px;
}
.bq-02__x {
width: 1px;
height: 1.6rem;
background: oklch(1 0 0/.12);
margin-left: auto;
}
.bq-02__meta {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: .7rem;
color: var(--mut);
}
.bq-02__chip {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11.5px;
color: var(--mut);
padding: 7px 13px;
border-radius: 99px;
box-shadow: 0 0 0 1px oklch(1 0 0/.1);
}
@container (width < 420px) {
.bq-02__row {
flex-wrap: wrap;
}
.bq-02__x,
.bq-02__meta {
display: none;
}
}
@media (prefers-reduced-motion: reduce) {
.bq-02 * {
transition-duration: .01ms !important;
}
}
```Here's a working CSS Blockquote from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind CSS Blockquote Component
Source: https://codefronts.com/snippets/css-blockquotes/tailwind-css-blockquote-component/
The Tailwind UI testimonial pattern — dark slate card, ring-1 border, avatar with an indigo ring, quote in font-semibold — rebuilt twice: once as the exact utility-class markup Tailwind users search for, and once as the plain-CSS translation that runs with zero build step (that's what renders here). Every utility is annotated with its CSS equivalent, so the demo doubles as a Tailwind-to-vanilla dictionary: ring-1 ring-white/10 is a box-shadow, not a border; divide-x is a sibling selector; the avatar ring is two stacked shadows.
## HTML
```html
<section class="bq-02" aria-label="Tailwind style blockquote component demo">
<div class="bq-02__stage">
<figure class="bq-02__card">
<svg class="bq-02__logo" viewBox="0 0 32 32" width="30" height="30" aria-hidden="true"><path d="M16 4l12 7v10l-12 7L4 21V11z" fill="none" stroke="currentColor" stroke-width="2.4"/><circle cx="16" cy="16" r="4.2" fill="currentColor"/></svg>
<blockquote class="bq-02__text-lg">
<p>“Utility classes made our design system reviewable. Every visual decision is right there in the diff — no hunting through stylesheets to find who set that margin.”</p>
</blockquote>
<figcaption class="bq-02__row">
<img class="bq-02__avatar" src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?q=80&w=160&auto=format&fit=crop" alt="" width="40" height="40" loading="lazy">
<div class="bq-02__who">
<div class="bq-02__name">Judith Black</div>
<div class="bq-02__role">CEO of Workcation</div>
</div>
<span class="bq-02__x" aria-hidden="true"></span>
<div class="bq-02__meta">ring-1 · ring-white/10</div>
</figcaption>
</figure>
<p class="bq-02__chip" aria-hidden="true">Tailwind pattern → plain CSS · ring = box-shadow · container query re-stack</p>
</div>
</section>
```
## CSS
```css
.bq-02,
.bq-02 *,
.bq-02 *::before,
.bq-02 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.bq-02 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
--bg: oklch(0.14 0.015 265);
--card: oklch(0.21 0.02 265);
--ink: oklch(0.97 0.005 250);
--mut: oklch(0.67 0.02 260);
--acc: oklch(0.6 0.19 275);
font-family: 'Segoe UI',system-ui,sans-serif;
color: var(--ink);
}
.bq-02__stage {
width: 100%;
height: 100vh;
height: 100svh;
display: grid;
place-items: center;
align-content: center;
gap: 24px;
padding: clamp(20px,5vw,56px);
background: radial-gradient(90% 70% at 50% 110%,oklch(0.22 0.05 275/.6),transparent),var(--bg);
overflow-y: auto;
}
.bq-02__card {
width: min(100%,36rem);
padding: 2rem;
border-radius: 1rem;
background: var(--card);
box-shadow: 0 0 0 1px oklch(1 0 0/.1),0 22px 50px oklch(0 0 0/.42);
container-type: inline-size;
}
.bq-02__logo {
color: var(--acc);
margin-bottom: 1.25rem;
display: block;
}
.bq-02__text-lg p {
font-size: 1.125rem;
line-height: 1.65;
font-weight: 600;
letter-spacing: -.008em;
text-wrap: pretty;
}
.bq-02__row {
display: flex;
align-items: center;
gap: 1rem;
margin-top: 1.5rem;
}
.bq-02__avatar {
width: 2.5rem;
height: 2.5rem;
border-radius: 99px;
object-fit: cover;
flex: none;
background: linear-gradient(135deg,oklch(0.5 0.1 275),oklch(0.35 0.06 300));
box-shadow: 0 0 0 2px var(--acc),0 0 0 4px color-mix(in oklch,var(--acc) 30%,transparent);
}
.bq-02__name {
font-size: .9rem;
font-weight: 650;
}
.bq-02__role {
font-size: .82rem;
color: var(--mut);
margin-top: 1px;
}
.bq-02__x {
width: 1px;
height: 1.6rem;
background: oklch(1 0 0/.12);
margin-left: auto;
}
.bq-02__meta {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: .7rem;
color: var(--mut);
}
.bq-02__chip {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11.5px;
color: var(--mut);
padding: 7px 13px;
border-radius: 99px;
box-shadow: 0 0 0 1px oklch(1 0 0/.1);
}
@container (width < 420px) {
.bq-02__row {
flex-wrap: wrap;
}
.bq-02__x,
.bq-02__meta {
display: none;
}
}
@media (prefers-reduced-motion: reduce) {
.bq-02 * {
transition-duration: .01ms !important;
}
}
```How this works
If you have Tailwind, this is the canonical component — memorize the shape, not the classes:
<figure class="rounded-2xl bg-slate-900 p-8 ring-1 ring-white/10">
<blockquote class="text-lg font-semibold text-white">
<p>“Tailwind made our design system reviewable…”</p>
</blockquote>
<figcaption class="mt-6 flex items-center gap-x-4">
<img class="h-10 w-10 rounded-full ring-2 ring-indigo-500" src="…" alt="">
<div><div class="font-semibold text-white">Judith Black</div>
<div class="text-slate-400">CEO of Workcation</div></div>
</figcaption>
</figure>The vanilla translation is where the learning is. ring-1 ring-white/10 is not a border — it compiles to box-shadow:0 0 0 1px rgb(255 255 255/.1), which is why rings never change layout size. rounded-2xl is border-radius:1rem; p-8 is padding:2rem; the avatar's ring-2 ring-indigo-500 stacks a second shadow outside the first. The demo's stylesheet writes each of these out under .bq-02 classes named after the utilities they mirror, so you can diff the two mentally line by line.
One upgrade over the stock Tailwind example: the card is a container query subject, so at under 420px of available space (not viewport) the figcaption re-stacks vertically — the component adapts wherever you paste it, which utilities alone can't express without arbitrary variants.
Make it yours
- Light mode: swap --card to white, --ink to slate-900 and the ring to ring-slate-900/10 — the shadow trick works identically on light backgrounds.
- Brand accent: the indigo ring and the logo mark both read from --acc; set it to your brand hue in oklch and the component re-skins in one line.
- Company logo row: Tailwind UI's variant adds a logo above the quote — drop an
<img class='h-8'>(height:2rem) as the figure's first child. - Grid of three: the card is width-capped at 36rem; remove the max-width and place three in a
grid-template-columns:repeat(3,1fr)for the classic testimonial wall.
Gotchas — read before shipping
- ring-* utilities are box-shadows: adding a real border on top double-strokes the card. Pick one system — this demo uses shadows exactly like Tailwind does.
- text-lg font-semibold on the quote but plain weight on the attribution is the pattern's whole hierarchy — flattening the weights is what makes DIY versions look off.
- Tailwind's slate-900 is a blue-tinted near-black; if your vanilla translation uses pure #111 the card looks dead. The demo uses oklch(0.21 0.02 265) to match the tint.
- The <img> needs empty alt (alt='') — the name is already adjacent text; announcing 'photo of Judith Black, Judith Black' is repetition, not accessibility.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 114+ | 17.5+ | 121+ | 114+ |
Floor set by oklch(), color-mix(), @container, text-wrap as this demo is written. The core technique itself goes back further — Chrome 111+.
Everything here is 2021-era CSS (box-shadow rings, border-radius, flex). The floor comes from oklch() tokens and the container query re-stack, which degrades to the horizontal layout.