docs / patterns / pullquote
Pullquote
a centered quote in display weight, with an optional attribution tied to it and a decorative ornament slot above.
intensity · structuresrsc · server
provenance
shaped from personal-websitelayer
core / patternsintensity
structures · organizes a region, stays out of the contentcomposition
long-form prose, landing sections, a manifesto beat between blocksany decorative node in the ornament slot, KajoSphere includednot for testimonials in a grid. one quote per sectionno interactive content in the ornament, it is aria-hiddena11y
attributed quotes renderfigure + figcaption · the ornament is aria-hiddenjest-axelive demo · try it out
Beauty that stays usable.
customize
childrenthe quote itself
attributionempty leaves a bare blockquote
ornamentdecorative flourish in the 80px slot
usage
import { Pullquote } from "usva/patterns/pullquote";
<Pullquote
attribution="usva, design principles"
> Beauty that stays usable.
</Pullquote>props
| prop | type | default | notes |
|---|---|---|---|
| children | ReactNode | — | the quote. rendered as a blockquote. |
| attribution | ReactNode | — | upgrades the wrapper to a figure and becomes its figcaption. |
| ornament | ReactNode | — | decorative flourish above the quote, in a fixed 80px slot. |
get it
npx shadcn add https://usva.build/r/pullquote.jsonsource · components/ui/pullquote.tsxexactly what this command copies
import * as React from "react";
import { cn } from "@/lib/utils";
export interface PullquoteProps
extends Omit<React.HTMLAttributes<HTMLElement>, "cite"> {
attribution?: React.ReactNode;
/**
* Decorative flourish above the quote. kajo passes a FogSphere here, which is
* Pro-licensed and cannot ship from this package. Keeping it a slot is what
* lets the quote itself be public.
*/
ornament?: React.ReactNode;
children: React.ReactNode;
}
/**
* A centered pull quote. Renders a `figure` only when attributed, so the
* attribution is programmatically tied to the quote rather than floating
* beneath it as a loose paragraph.
*/
export const Pullquote = React.forwardRef<HTMLElement, PullquoteProps>(
({ className, attribution, ornament, children, ...props }, ref) => {
const body = (
<>
{ornament != null && (
<div
aria-hidden="true"
data-pullquote-ornament=""
className="mx-auto mb-4 size-20"
>
{ornament}
</div>
)}
<blockquote className="text-balance text-[clamp(1.125rem,2.5vw,1.625rem)] font-bold leading-[1.4] tracking-[-0.01em] text-ink">
{children}
</blockquote>
</>
);
const shell = cn("mx-auto max-w-3xl py-4 text-center", className);
if (attribution == null)
return (
<div
ref={ref as React.Ref<HTMLDivElement>}
className={shell}
{...props}
>
{body}
</div>
);
return (
<figure ref={ref as React.Ref<HTMLElement>} className={shell} {...props}>
{body}
<figcaption className="mt-3 font-mono text-sm text-muted">
{attribution}
</figcaption>
</figure>
);
},
);
Pullquote.displayName = "Pullquote";