---
title: The Component Showcase
description: "A living reference for every component available when writing a post on this blog: typography, links, lists, media, footnotes and more, each shown live."
date: 2026-07-19
updated: 2026-10-29
tags: [design-system, components, reference]
source: https://blog.lenysauzet.com/posts/design-system
---

This article renders every content component the blog offers, so each one can be
seen live and its pattern copied. It is not documentation — it is a visual index.

## Typography

Body copy is a paragraph. It carries **strong emphasis** for the load-bearing
words, _italic emphasis_ for a lighter touch, and `inline code` for identifiers,
file names and anything typed verbatim.

## Heading level two

### Heading level three

#### Heading level four

Headings nest from level two (`##`) downward; level one is reserved for the
article title.

## Anchor

<div className="flex flex-col items-start gap-4">
  <Anchor href="https://github.com/LenySauzet">@LenySauzet</Anchor>
  <Anchor href="https://youtube.com">YouTube</Anchor>
  <Anchor href="https://developer.mozilla.org">MDN Web Docs</Anchor>
  <Anchor href="/">Home</Anchor>
  <Anchor href="https://github.com/LenySauzet" discreet>
    @LenySauzet
  </Anchor>
  <Anchor href="/" direction="left">
    Back
  </Anchor>
</div>

## Badge

<div className="flex gap-2 flex-wrap">
  <Badge variant="info">Info</Badge>
  <Badge variant="success">Success</Badge>
  <Badge variant="warning">Warning</Badge>
  <Badge variant="danger">Danger</Badge>
</div>

## Blockquote

> Almost before we knew it, we had left the ground.

## Support callout

<SupportCallout />

## Callouts

<Callout>
  A note, the default. It can hold `inline code`, [links](https://developer.mozilla.org)
  and any other inline markup.
</Callout>

<Callout variant="warning">A warning, for what is easy to get wrong.</Callout>

<Callout variant="danger">A caution, for what can break.</Callout>

<Callout label="Compatibility">

A label replaces the variant's name, and any block can sit inside:

```wgsl
stateReadTexture: texture_2d<f32>,
stateWriteTexture: texture_storage_2d<rgba8unorm, write>
```

Its corners shrink so they nest in the callout's, as do a tweet's, a table's, an
image's and a video's.

</Callout>

## Details/Summary

<Details summary="Summary: Some short text">
  Content. Some long text nested inside the component. Useful to avoid long,
  optional content. It can take some simple strings or some other custom React
  components. As you want!
</Details>

## Lists

- First item
- Second item
- Third item

1. First step
2. Second step
3. Third step

- Parent item
  1. Nested first
  2. Nested second
- Another parent
  - Nested arrow one
  - Nested arrow two

## Card

<Card title="A card title">
  Cards group related content on a raised surface. The body accepts any markdown,
  `inline code`, links and more.
</Card>

<Card>Without a title, the card is body-only and has no separator.</Card>

## Buttons

<ButtonShowcase />

## Form components

<InputShowcase />

## Toggles

<ToggleShowcase />

## Slider

<SliderShowcase />

## Select

<SelectShowcase />

## Code Block

A fenced block with a title bar (copy button included) and highlighted lines:

```tsx title="greet.ts" {6-8}
console.log('hello world');

/**
 * Some comments
 */
function sayHi(name) {
  const message = `hi ${name}`;
  return message;
}
```

A changed line ends in `// [!code ++]` or `// [!code --]`, and copying takes only the new code:

```diff
 function greet(name: string) {
-  return 'Hello ' + name + '!';
+  return `Hello ${name}!`;
 }
```

`variant="info"`, `"warning"` and `"danger"` are for logs and output, titled after their level unless given a title:

```txt variant="info"
ready - started server on 0.0.0.0:3000, url: http://localhost:3000
```

```txt variant="warning"
Warning: Each child in a list should have a unique "key" prop.
    Check the render method of `PostList`.
```

```txt title="TypeError" variant="danger"
TypeError: Cannot read properties of undefined (reading 'map')
    at MessageList (components/message-list.tsx:18:22)
    at renderWithHooks (react-dom.development.js:16305:18)
```

A block longer than 24 lines folds to its first 16:

```ts title="easing.ts"
type Easing = (t: number) => number;

export const linear: Easing = (t) => t;

export const easeInQuad: Easing = (t) => t * t;

export const easeOutQuad: Easing = (t) => t * (2 - t);

export const easeInOutQuad: Easing = (t) =>
  t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;

export const easeInCubic: Easing = (t) => t ** 3;

export const easeOutCubic: Easing = (t) => 1 - (1 - t) ** 3;

export const easeInOutCubic: Easing = (t) =>
  t < 0.5 ? 4 * t ** 3 : 1 - (-2 * t + 2) ** 3 / 2;

export const easeOutBack: Easing = (t) => {
  const c1 = 1.70158;
  const c3 = c1 + 1;
  return 1 + c3 * (t - 1) ** 3 + c1 * (t - 1) ** 2;
};

export const easeOutElastic: Easing = (t) => {
  if (t === 0 || t === 1) return t;
  const c4 = (2 * Math.PI) / 3;
  return 2 ** (-10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1;
};

// Runs an easing over a duration, calling back with each eased value.
export function animate(duration: number, ease: Easing, onFrame: (value: number) => void) {
  const start = performance.now();
  const tick = (now: number) => {
    const t = Math.min((now - start) / duration, 1);
    onFrame(ease(t));
    if (t < 1) requestAnimationFrame(tick);
  };
  requestAnimationFrame(tick);
}
```

## Sandpack Code Block

<Sandpack
  template="react"
  dependencies={{ 'framer-motion': 'latest' }}
  files={{
    '/App.js': `import { motion } from 'framer-motion';
import './scene.css';

function WavingHand() {
return (

<motion.span
style={{ display: 'inline-block', transformOrigin: '70% 70%' }}
animate={{ rotate: [0, 18, -8, 18, 0] }}
transition={{ duration: 1.6, repeat: Infinity, repeatDelay: 0.6 }} >
👋
</motion.span>
);
}

export default function App() {
  return (
    <h1>
      Hi <WavingHand /> !
    </h1>
  );
}
`,
    '/scene.css': `html {
  background: #08080b;
}

body {
color: white;
}

h1 {
font-family: sans-serif;
font-size: 2.75rem;
font-weight: 600;
}
`,
}}
/>

## Math Equations

Inline math flows in a sentence — Euler's identity $e^{i\pi} + 1 = 0$ — while a
display equation centres on its own line and scrolls if it runs wide:

$$
v_o = \begin{bmatrix}
x\sqrt{1 - \dfrac{y^2}{2} - \dfrac{z^2}{2} + \dfrac{y^2 z^2}{3}} \\[0.5em]
y\sqrt{1 - \dfrac{x^2}{2} - \dfrac{z^2}{2} + \dfrac{x^2 z^2}{3}} \\[0.5em]
z\sqrt{1 - \dfrac{x^2}{2} - \dfrac{y^2}{2} + \dfrac{x^2 y^2}{3}}
\end{bmatrix}
$$

## Images

<Image src="https://cdn.lenysauzet.com/images/blog/Monet_Meadow-with-Poplars.jpg" alt="Monet's Meadow with Poplars" />

## Before / After Image

<Fullbleed>
  <BeforeAfterImage
    alt="This blog in its dark theme beside its light one."
    beforeSrc="https://cdn.lenysauzet.com/images/blog/blog-dark.png"
    afterSrc="https://cdn.lenysauzet.com/images/blog/blog-light.png"
    defaultPosition={50}
  />
</Fullbleed>

## Slideshow

<Slideshow
  alt="Three images, one frame."
  images={[
    { src: 'blog/slide-1.jpg', alt: 'The crescent moon over the curve of the Earth, its atmosphere a thin blue line.' },
    { src: 'blog/slide-2.jpg', alt: 'Cumulus clouds piled under a clear blue sky.' },
    { src: 'blog/slide-3.jpg', alt: 'A painting of a ship in a storm, its sails torn under breaking waves.' },
  ]}
/>

### Autoplay

<Slideshow
  alt="The same three, playing on their own."
  images={['blog/slide-1.jpg', 'blog/slide-2.jpg', 'blog/slide-3.jpg']}
  autoPlay
/>

## Video

<VideoPlayer
  src="https://cdn.lenysauzet.com/videos/blog/halftone-compilation-compressed.mp4"
  title="Halftone compilation"
  autoPlay
  muted
  loop
  width={663}
  height={398}
/>

## Tweet

A post on X, fetched at build and drawn in the site's own markup.

[A post on X](https://x.com/i/status/1772606761695879419)

## Charts

A figure that carries axes.

<ChartShowcase />

## Geometric diagrams

SVG, drawn from maths a test can read.

<RaySphere />

Leaders, for names that cannot sit beside their subject.

<Bezier />

A loupe.

<Coverage />

A surface, in three dimensions.

<Wave />

Driven by time.

<Lerp />

## Rendered surfaces

A fragment shader, driven by its uniforms and by time.

<LitWave />

Over an image.

<Halftone />

Over a video.

<VideoHalftone />

## Tables

GFM pipes, mapped onto the shadcn primitive.

| Approach | Ships to the browser | Authoring |
| --- | --- | --- |
| GFM pipes | nothing, the plugin runs at build | a row per line |
| `<Table>` composed by hand | nothing, still a Server Component | JSX, for what pipes cannot say |
| TanStack Table | 31 kB, and `'use client'` | a column definition per table |

Alignment comes from the delimiter row.

| Left | Centre | Right |
| :--- | :----: | ----: |
| `--primary` | 262.04 | 1.0 |
| `--border` | 17 presets | 0.5 |

Past the measure, a table scrolls inside its own edge.

| Preset | Hue | Lightness | Light | Dark | Floor | Tailwind |
| --- | ---: | ---: | ---: | ---: | ---: | --- |
| Blue | 259.8 | default | 4.06 | 7.21 | 3.79 | blue-500 |
| Violet | 292.7 | +0.02 | 3.91 | 6.88 | 3.79 | violet-500 |
| Teal | 182.5 | +0.05 | 3.84 | 6.44 | 3.79 | teal-500 |

## Dividers

---

## Footnotes

A reference marks a spot <FootnoteRef id="1" />, and the list below resolves it.

<FootnotesList
  notes={[
    {
      id: 1,
      content: (
        <p>
          Footnotes are resolved by{' '}
          <a href="https://github.com/LenySauzet/blog.lenysauzet.com">
            the FootnotesList component
          </a>
          , which renders this list and links each entry back to its reference.
        </p>
      ),
    },
  ]}
/>
