opensourceui
GitHubTwitter/X
  1. Home
  2. Components
  3. Text
  4. Editorial Quote
Back to Text

Components / Text

Editorial Quote

Free Text React component — EditorialQuoteCard. MIT licensed, copy-paste ready for Next.js and Tailwind CSS.

Pull quote with issue metadata and a highlighted word inside the line — author and role at the bottom. Built for case studies and long reads.

Preview

Issue 06 · Design
Good design is as little design as possible — but every pixel must earn its place.

Dieter Rams

Industrial Designer

Setup

How to use

Free for personal and commercial use. No UI attribution required. Include the MIT copyright notice when copying component source into your project. Read the MIT license.

  1. 1

    Run in your terminal:

    $npm install clsx tailwind-merge lucide-react
  2. 2

    Copy lib/cn.ts below. Skip if you already have cn().

  3. 3

    Copy the code below and create components/text/editorial-quote-card.tsx in your project.

  4. 4

    Import and render:

    Example

    import { EditorialQuoteCard } from "@/components/text/editorial-quote-card";

    <EditorialQuoteCard />

lib/cn.ts

1
2
3
4
5
6
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
 
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}

components/text/editorial-quote-card.tsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import { forwardRef, type ComponentPropsWithoutRef } from "react";
 
import { cn } from "@/lib/cn";
 
import { Quote } from "lucide-react";
 
export type EditorialQuoteCardProps = Readonly<
{
quote?: string;
author?: string;
role?: string;
issue?: string;
accentWord?: string;
} & ComponentPropsWithoutRef<"div">
>;
 
// Production-ready Editorial Quote component — styled with Tailwind CSS.
export const EditorialQuoteCard = forwardRef<
HTMLDivElement,
EditorialQuoteCardProps
>(
(
{
className,
quote = "Good design is as little design as possible — but every pixel must earn its place.",
author = "Dieter Rams",
role = "Industrial Designer",
issue = "Issue 06 · Design",
accentWord = "pixel",
...props
},
ref,
) => {
const parts = quote.split(new RegExp(`(${accentWord})`, "i"));
let segmentOffset = 0;
const segments = parts.map((part) => {
const segment = {
id: `quote-part-${segmentOffset}`,
part,
};
segmentOffset += part.length;
return segment;
});
 
return (
<div
ref={ref}
data-slot="editorial-quote-card"
className={cn(
"w-sm border border-neutral-200 bg-[#f6f2eb] p-5 font-sans sm:p-6",
className,
)}
{...props}
>
<div
data-slot="editorial-quote-card-meta"
className="mb-4 flex items-center justify-between border-b border-neutral-200 pb-3"
>
<span className="font-mono text-[10px] font-semibold tracking-widest text-neutral-500 uppercase">
{issue}
</span>
<Quote size={18} className="text-neutral-400" />
</div>
 
<blockquote
data-slot="editorial-quote-card-quote"
className="text-lg leading-snug font-semibold tracking-tight text-neutral-700 sm:text-xl"
>
{segments.map(({ id, part }) =>
part.toLowerCase() === accentWord.toLowerCase() ? (
<span
key={id}
className="rounded-sm bg-neutral-300/60 px-1 text-neutral-800"
>
{part}
</span>
) : (
<span key={id}>{part}</span>
),
)}
</blockquote>
 
<div
data-slot="editorial-quote-card-author"
className="mt-5 flex items-center gap-3"
>
<div className="h-px flex-1 bg-neutral-200" />
<div className="text-right">
<p className="text-sm font-medium text-neutral-600">{author}</p>
<p className="text-[11px] text-neutral-500">{role}</p>
</div>
</div>
</div>
);
},
);
 
EditorialQuoteCard.displayName = "EditorialQuoteCard";
PreviousNext

On this

page

Jump to a section on this page.

  • lib/cn.ts
  • components/text/editorial-quote-card.tsx

Sponsor spot · demo preview

Logo

Your brand name

Your tagline or category

A short pitch about your product or service goes here. This is a preview of how sponsor cards will look in this sidebar.

Your call to action

This slot is available. Sponsor Opensource UI and reach developers browsing components every day.