Skip to content
ssntl/ui

Blockquote

A pull quote that adds its own curly quotes and hangs the opening one outside the text.

“We opened the store on a Friday and took our first order before lunch.”

Ana López, Studio Norte

Installation

$ pnpm dlx shadcn@latest add @ssntl/blockquote

Usage

tsx
import { Blockquote, BlockquoteCite, BlockquoteText } from "@/components/ui/blockquote"

<Blockquote>
  <BlockquoteText>We took our first order before lunch.</BlockquoteText>
  <BlockquoteCite>Ana López, Studio Norte</BlockquoteCite>
</Blockquote>

Rules

What this component expects from you, as it ships in components/ui/blockquote.md next to the code. The full file adds when to use it, keyboard, the UI foundations it applies and every shared rule.

components/ui/blockquote.md
## Rules for Blockquote

- **Hanging marks.** `BlockquoteText` adds the curly quotes itself and hangs the opening one, so the first letter lines up with the name below.
- Pass the words only, without quote marks; use real people's words with their permission.
- The cite names the person, then role or source, in caption size.
Open the full rules file (opens in a new tab)

Code

components/ui/blockquote.tsx
import * as React from "react"

import { cn } from "@/lib/utils"

// A pull quote. Hanging marks: the component adds the curly quotes itself
// and hangs the opening one outside the block (hang-quote), so the first
// letter lines up with the text above and below. Large type also pulls back
// its side bearing (optical-edge).
function Blockquote({ className, ...props }: React.ComponentProps<"figure">) {
  return (
    <figure
      data-slot="blockquote"
      className={cn("grid gap-4", className)}
      {...props}
    />
  )
}

function BlockquoteText({
  className,
  children,
  ...props
}: React.ComponentProps<"blockquote">) {
  return (
    <blockquote
      data-slot="blockquote-text"
      className={cn("hang-quote text-title text-balance", className)}
      {...props}
    >
      <p>“{children}”</p>
    </blockquote>
  )
}

/** Who said it: name, then role or source, in caption size. */
function BlockquoteCite({
  className,
  ...props
}: React.ComponentProps<"figcaption">) {
  return (
    <figcaption
      data-slot="blockquote-cite"
      className={cn("text-caption text-muted-foreground", className)}
      {...props}
    />
  )
}

export { Blockquote, BlockquoteCite, BlockquoteText }