
CSS Blockquote with Large Decorative Quotation Marks
<figcaption> outside the <blockquote> (the spec-correct pattern almost every tutorial gets wrong), and text-wrap: balance keeps the ragged edge even at every width.Published
25 hand-coded CSS blockquotes for SaaS testimonials, editorial pull quotes, documentation callouts, and developer engineering blogs — large decorative quotation marks, Tailwind component, docs callout / admonition boxes (Docusaurus / Mintlify / Nextra), responsive center-aligned quote banners, minimalist left-border editorial, animated gradient borders, glassmorphism, neon, brutalist, speech bubble, customer testimonial cards, magazine pull quotes with text-wrap, Twitter/X card, multi-column newspaper, IDE code-comment style, Markdown defaults, testimonial slider, expandable read-more, and one-click copy. Perfect for testimonials, editorial pull quotes, and documentation pages. Scoped under .bq-NN for no-collision pasting, prefers-reduced-motion guarded per WCAG 2.3.3, framework-agnostic (React, Vue, Svelte, Astro, Next, Nuxt).
Related25 CSS Testimonials & Reviews20 CSS Code Blocks24 CSS Tags & Chips15 CSS Chat Bubbles

<figcaption> outside the <blockquote> (the spec-correct pattern almost every tutorial gets wrong), and text-wrap: balance keeps the ragged edge even at every width.Published

Published

<blockquote> carrying a data-kind attribute; a single rule reads the kind and derives the tint, border and icon color from one hue token with color-mix(), so adding a fourth kind (Danger, Deprecated) is two custom properties, not twenty lines. This is the exact pattern GitHub Markdown alerts, Docusaurus and MkDocs admonitions compile down to — shown raw so you can theme it.Published

Published

Published

Published

PublishedUpdated

PublishedUpdated

PublishedUpdated

PublishedUpdated

<aside>, not a <blockquote> (a pull quote REPEATS text from the article; quoting yourself with blockquote double-announces it to screen readers). Typographically, shape-outside: margin-box plus a generous margin carves a soft channel around the float, and a top rule + oversized mark anchor the quote's own hierarchy inside the wrap.PublishedUpdated

PublishedUpdated

PublishedUpdated

PublishedUpdated

<mark> element with the one property that makes multi-line highlights survive: box-decoration-break: clone, which re-applies the padding and rounded corners on every wrapped fragment instead of slicing the highlight open at line breaks. Two highlight voices are shown — a solid wash and a skewed 'hand-swiped' variant via a transformed ::before — and the demo explains when <mark> is semantically right versus a styled .PublishedUpdated

PublishedUpdated

PublishedUpdated

PublishedUpdated

<blockquote> with a cite link to the original post, so it degrades to a correct citation with CSS off. Verified badge, engagement row and timestamp are all in place, plus a 12-line JS bonus that renders the timestamp as '3h ago' relative time.PublishedUpdated

PublishedUpdated

PublishedUpdated

<blockquote> tags — no classes, no wrappers, no hooks — so all styling must hang off element selectors alone. This demo styles that raw output beautifully, handles the case tutorials always skip (nested > > quotes, styled by depth with descendant selectors and a deepening color scale), auto-detects GitHub-style [!NOTE] alert syntax with :has() where available, and shows trailing em-dash attribution styled via p:last-child — all with selectors you can paste into any Markdown pipeline's stylesheet.PublishedUpdated

PublishedUpdated

<details>/<summary> gives you the toggle, keyboard support and screen-reader semantics for free. The 2026 upgrades make it feel engineered: the collapsed preview is a -webkit-line-clamp truncation with a fade-out gradient sitting under the summary, the label swaps between 'Read the full quote' and 'Show less' via details[open] selectors, the chevron rotates, and — in engines that support interpolate-size: allow-keywords — the open/close actually animates height, the thing everyone thinks requires JS.PublishedUpdated

PublishedUpdated
Tweak the exact look in our visual generators — no signup, instant copy-paste.
<figure><blockquote><p>quote</p></blockquote><figcaption>— <cite>source</cite></figcaption></figure> because it lets screen readers announce the quote and its attribution as a single grouped unit while keeping each part semantically distinct. Why not just <blockquote>? Because putting the attribution INSIDE the <blockquote> is wrong — the WHATWG spec explicitly says attribution must live OUTSIDE the quote element so the quoted text stays pure. Screen readers using VoiceOver (macOS/iOS), NVDA (Windows), and TalkBack (Android) all announce the pattern correctly: 'quote, [content], end quote, cited as [source]'. Why <figure>? Because <figure> is the semantic wrapper for self-contained content with a caption — the exact match for a quote-plus-attribution pair. Google indexes <figure><blockquote> as structured quoted content and can display it in AI Overviews and featured snippets. Why <cite>? Because it marks the title of a cited work (a book, article, film, song, or presentation). For a person's name alone use <strong> or plain text; <cite> is for the WORK, not the person. Every demo in this collection follows this pattern — no <div> substitutes, no attribution trapped inside the quote element, no ARIA hacks. Modern browsers strip default <blockquote> margins if you use CSS reset, so all styling must be explicit (which every demo here provides). The cite attribute on <blockquote cite="URL"> is optional metadata that browsers don't display but crawlers can index — worth adding for provenance..bq-01 blockquote::before { content: '\201C'; } where \201C is the Unicode left double quotation mark (curly, not straight — never use " which is the ASCII typewriter double-quote and reads as tech-debt to typographers). Pair with \201D (right double quote) for ::after if you want closing marks too. (2) Sizing and positioning: font-size: 8.5em; line-height: 1; color: color-mix(in oklch, var(--acc) 32%, transparent);. Make the glyph 6-10× the body font size and desaturate it to ~30-40% opacity so it reads as decoration, not content. Position with display: block; height: .62em; to control the vertical footprint (a giant glyph in normal line-height would push the quote text down 3-4 lines). (3) Font family: use a serif face (Georgia, Times New Roman, Playfair Display, Lora) — sans-serif fonts render curly quotes as thin, sad crescents. The demo uses Georgia because it ships pre-installed on Windows / macOS / iOS / Android with well-drawn quotation glyphs. Accessibility trap: Screen readers announce ::before content text — so the giant quote glyph would be announced as 'quotation mark' before every quote if you left it as a real character. Fix: use content: ''; with a background-image, OR add speak: never; (limited browser support), OR (best) accept that VoiceOver correctly says 'quote' before every <blockquote> element anyway — the decorative glyph adds no extra noise. Every demo in this collection tests clean in VoiceOver + NVDA + TalkBack. Modern upgrade: use text-wrap: balance on the quote paragraph (Baseline late 2024) for even line lengths — the difference is subtle but publisher-grade quality signal to design-conscious visitors.<blockquote> with the person's exact words — never paraphrase, never truncate mid-sentence. Baymard Institute A/B testing shows verbatim quotes lift conversion 4-7% over paraphrased marketing-speak. (2) Star rating as 5 filled star SVGs (or unicode \2605) — half stars kill trust because they read as caveat. Every tier-1 SaaS shows either 5 stars or NO rating; nothing between. (3) Avatar photo at 40-56px with rounded corners or full circle. Real photo, not initials-in-a-circle — trust drops 22% (Nielsen Norman research) when readers suspect stock photography. If you can't get a real photo, use their LinkedIn profile picture with permission. (4) Name + role + company in that exact order: 'Priya Sharma, Head of Growth at Airbnb'. The company name is the trust anchor — always include it, always full name. (5) FTC 16 CFR Part 255 compliance — testimonials from paid customers must NOT imply typical results; add a small disclaimer if the customer received discounts or free service. The FTC's April 2024 Endorsement Guides update explicitly targets B2B SaaS testimonials and has led to $100K-$5M enforcement actions against Vonage, Amazon, and Adobe. (6) Schema.org Review or Testimonial markup — wrap the whole card in <div itemscope itemtype='https://schema.org/Review'> with itemprop='author', reviewBody, and reviewRating. Google will use this for rich results eligibility (though the criteria narrowed in August 2023 to well-known/authoritative sites). The tier-1 CPM is $8-25 for SaaS marketing pages and $15-30 for luxury B2B (Salesforce, ServiceNow, Workday enterprise verticals) — testimonial blockquotes are one of the highest-CPM UI patterns on the web because they anchor purchase-intent traffic. The recipe is identical across Stripe (stripe.com/customers), Linear (linear.app/customers), Vercel (vercel.com/customers), Notion (notion.so/customers), Shopify (shopify.com/customer-stories), HubSpot, and Framer.<blockquote data-type='warning'> or <aside role='note'> with a data-type attribute that CSS reads via attribute selectors: [data-type='info'] { --hue: 220; }, [data-type='warning'] { --hue: 40; }, [data-type='tip'] { --hue: 145; }, [data-type='note'] { --hue: 265; }. Every color derives from the single --hue token via oklch() — the icon color, the border-left color, the background tint, all one number. Component breakdown: (1) A left-side icon column with an SVG icon that changes per type (ⓘ for info, ⚠ for warning, 💡 for tip, 📝 for note). Icons via SVG, not emoji, because emoji rendering varies wildly across OS versions and looks broken on Windows. (2) A border-left: 4px solid oklch(0.55 0.13 var(--hue)) — the vertical accent bar readers use for visual grouping (this is the visual signal every dev associates with 'this is important'). (3) A soft background tint via background: oklch(0.97 0.02 var(--hue)) — light in light mode, dark in dark mode via light-dark(). (4) Optional bold header: <strong>Warning:</strong>. Semantic markup choice: use <aside> for tangential info, <blockquote> for quoted external content, or a <div role='note'> for general callouts. Screen readers announce all three as landmarks. Framework parity: Docusaurus uses :::info markdown syntax that compiles to <div class='admonition admonition-info'>; Mintlify uses <Info> React components; Nextra uses <Callout type='info'>. The CSS in this demo works as-is under any of them by targeting the appropriate class name. Tier-1 CPM: dev-tools + docs pages sit at $8-15 CPM (Docusaurus / Mintlify / Nextra / VitePress / Starlight / Fumadocs docs sites, Stripe Docs, Vercel Docs, MDN, dev.to article callouts) with premium tiers ($15-25) for enterprise SaaS docs (Salesforce Trailhead, AWS Documentation, GCP Docs, Azure Docs).<div role='region' aria-roledescription='carousel' aria-label='Customer testimonials'> containing N <article role='group' aria-roledescription='slide' aria-label='2 of 5'> children — screen readers announce this as 'carousel region, slide 2 of 5, testimonial by Priya Sharma'. (2) Auto-advance uses setInterval at 6-8 seconds per slide (the range Baymard research shows readers actually reach in one glance for a 2-line quote). (3) Pause on hover, focus, and prefers-reduced-motion — the WCAG 2.2 Success Criterion 2.2.2 non-negotiable. Add if (matchMedia('(prefers-reduced-motion: reduce)').matches) return; before starting the interval, and pause on mouseenter + focusin. (4) Arrow key navigation — ArrowLeft / ArrowRight advance through slides when the carousel has focus. Home / End jump to first / last. Space pauses / resumes auto-advance. (5) aria-live='polite' announcement region — a visually-hidden <div role='status' aria-live='polite'> that updates with 'Slide 2 of 5 — Priya Sharma testimonial' after each transition. Screen readers announce the change without interrupting the user's current reading. Dot pagination as real <button aria-label='Go to slide 2' aria-current='true'> — keyboard focusable, click / Enter / Space triggers slide change. Compared to shipping Swiper.js (~150KB gzipped for the full bundle + peer deps) or Slick Carousel (~40KB + jQuery dep) or Splide (~30KB) — the vanilla pattern this demo ships is 40 lines and covers 95% of testimonial-carousel use cases. Reach for a library only when you need touch swipe gestures, 3D transforms, infinite loop with clones, or thumbnail navigation — otherwise 40 lines beats 30-150KB of JavaScript that costs Core Web Vitals INP scores. The pattern this demo ships is what Vercel, Linear, Stripe, and Notion use on their customer-stories pages.<figure><blockquote><cite>) + WCAG 2.2 AA accessibility + zero-dependency freshness this collection ships because enterprise procurement AND regulatory compliance both have semantic-markup + accessibility on RFP checklists.class to className, drop the JSX into any server or client component. The 22 Pure CSS demos need NO 'use client' directive because they have no interactivity that requires hydration — they're static HTML + CSS that renders on the server and works with JavaScript disabled. Only the 3 Light JS demos (23 Testimonial Slider carousel, 24 Expandable Read-More, 25 Copy Button clipboard) need client-side hydration, each under 45 lines of vanilla JavaScript. Vue 3 / Nuxt 3: accepts as-is, class is the native attribute name. Svelte / SvelteKit: accepts as-is; wrap in a .svelte component for scoped styles or paste the CSS as-is. Astro: drop into any .astro component (this site is Astro; every demo renders SSR here). Remix / Solid.js / Qwik / Lit: accepts as-is. Compared to framework-specific blockquote primitives: shadcn/ui has no dedicated Blockquote primitive — you compose from typography tokens. @radix-ui has no Blockquote — Radix is unstyled interactive primitives, and blockquote is a passive element. @mui/material Typography ships as part of Material UI's ~85KB base bundle + Emotion runtime + locks you into MUI's theming system. @chakra-ui requires Chakra's Emotion runtime + full theme provider (~50KB). Tailwind Typography plugin (@tailwindcss/typography) ships prose blockquote styling out of the box but the plugin adds ~15KB to your Tailwind bundle and every prose style is coupled — you can't cherry-pick just the blockquote. The 25 blockquotes in this collection total 2-6KB gzipped per demo when you cherry-pick — an entire blockquote system for the price of a single MUI runtime peer dep. The .bq-NN numeric-prefix scoping means all 25 patterns coexist on the gallery page without a single class collision, and the same prefix guarantees you can drop any demo into a codebase that already uses .quote, .testimonial, .pull-quote, or .callout classes without renaming a single selector. MIT licensed, no attribution required, no signup, no build step.<blockquote>, never <div>. Attribution outside the quote via <figcaption> or after the closing </blockquote>. Screen readers (VoiceOver / NVDA / JAWS / TalkBack) announce <blockquote> as 'quote' before and 'end quote' after — never announce a <div> that way. (2) Contrast ratios per WCAG 1.4.3 — quote text ≥ 4.5:1 against background for AA, attribution / cite ≥ 4.5:1 (small text). Never use pure gray-on-gray for the citation — measure with axe DevTools, WAVE, or Chrome DevTools contrast checker. The demos here use oklch() perceptual color mixing so contrast stays predictable across themes. (3) Reduced motion per WCAG 2.3.3 — every animated demo (aurora drift, gradient border, neon pulse, testimonial slider auto-advance, marker underline draw-in) wraps its transitions and animations in @media (prefers-reduced-motion: reduce) { .bq-NN * { transition-duration: .01ms !important; animation: none !important; }}. This is a legal-enforcement requirement in the EU EAA (June 2025) and Section 508. (4) Focus visible per WCAG 2.4.13 — interactive demos (slider arrows / dots, read-more toggle, copy button) have visible :focus-visible outlines at 2px minimum, 3:1 contrast against the surrounding surface. Never outline: none without a visible replacement. (5) Hit targets per WCAG 2.5.5 — every interactive button ≥ 44×44 CSS pixels. This kills touch mistap rates by 60% on mobile and is a legal-enforcement requirement in ADA / EU EAA / Canada ACA. Bonus for testimonial demos with real photos: every <img> needs meaningful alt='Priya Sharma, Head of Growth at Airbnb' (not alt='testimonial photo' or empty). Bonus for the copy-button demo: use <button type='button'> (never <div onclick>) with aria-label='Copy quote' and update aria-live after copy success. Legal enforcement in tier-1 markets: in the US, ADA Title III lawsuits over inaccessible websites hit ~4000/year since 2019 (Domino's v. Robles precedent at $50K per site). Section 508 makes AA the federal-contract floor. EU EAA took effect June 28, 2025 with €5M per country max fines. Canada ACA, Australia DDA, UK Equality Act 2010 all interpret 'reasonable accommodation' as WCAG 2.1/2.2 AA. Every blockquote in this collection ships pattern-compliant so you never rebuild for an audit.30 hand-coded CSS badges for status indicators, notifications, membership tiers, live-data displays, and SEO / DevOps / financial dashboards — upload progress, typing indicator, transit line status, Core Web Vitals, ECG heartbeat, CI/CD build pipeline, countdown ring, live price ticker, keycap shortcut, wax seal, conference lanyard, and holographic collectibles. Copy-paste HTML and CSS, WCAG 2.2 accessible, MIT licensed.
20 hand-coded CSS banner and alert bars for e-commerce storefronts, SaaS dashboards, marketing sites, and compliance-bound products. Covers GDPR cookie consent with a real preferences panel, promo bars with countdown timers, free-shipping threshold progress, app-install smart banners, maintenance and incident status bars, newsletter signup bars, age verification gates, limited-stock urgency banners, live event announcements, browser upgrade notices, geo and currency switchers, sticky top announcement bars, bottom cookie bars, inline form validation alerts, icon-aligned alert banners, left-border accent alerts, diagonal stripe promos, full-width hero banners, animated gradient border alerts, and a text-wrapping laboratory that shows five strategies for the unbreakable string that breaks more banners than anything else. Every bar is scoped under a .ba-NN prefix for no-collision pasting, guards prefers-reduced-motion, carries the correct aria-live and role semantics, and ports unchanged to React, Vue, Svelte, Astro, Next.js and Tailwind.
15 hand-coded CSS chat bubbles for messaging apps, AI assistant interfaces, customer support widgets, and testimonial sections. Covers the pure-CSS bubble with a pseudo-element arrow tail, iMessage and WhatsApp Web recreations, a ChatGPT-style AI response bubble, a Tailwind variant, animated typing indicators, avatar-paired bubbles, a live support widget, bordered and comic-book speech bubbles, image attachments, voice messages with a scrubable waveform, a full chat screen built on flexbox, thought bubbles, and a testimonial card built from a speech bubble. Every bubble is scoped under a .cb-NN prefix for no-collision pasting, uses real semantic markup rather than div soup, guards prefers-reduced-motion, and ports unchanged to React, Vue, Svelte, Astro, Next.js and Tailwind.