# Media

> Images, video, audio, files and PDFs.

Each example below is a real Notion block, rendered by notionic's built-in components, followed by a recipe to change it.

Files uploaded to Notion have signed URLs that expire after an hour, longer than most pages are cached. Point them at a route that signs them again:

```typescript
// Customize · file-url.tsx
// Every uploaded image, video, audio, file and PDF goes through it. External URLs don't.
<NotionRenderer blocks={blocks} transformFileUrl={({ blockId }) => `/api/notion/file/${blockId}`} />
```

# Image

**In Notion:** type `/image`, then upload a file or paste a link.

![A mountain landscape](https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=1200)

**Renders as:** an `<img>`, lazily loaded, with a soft edge that follows its shape, and the caption below. See [Supported blocks](https://notionic.dev/docs/supported-blocks).

```typescript
// Customize · image.tsx
import Image from "next/image"
import { defaultComponents, plainText, RichText, type BlockProps } from "notionic"

const BuiltInImage = defaultComponents.image!

// next/image for external images (add their hosts to next.config); the built-in one for uploads.
export function NextImage(props: BlockProps<"image">) {
  const { image } = props.block
  if (image.type !== "external") return <BuiltInImage {...props} />
  return (
    <figure className="flex flex-col gap-2">
      <Image
        src={image.external.url}
        alt={plainText(image.caption)}
        width={1200}
        height={800}
        className="h-auto w-full rounded-lg"
      />
      {image.caption.length ? (
        <figcaption className="text-sm text-muted-foreground">
          <RichText text={image.caption} context={props.context} />
        </figcaption>
      ) : null}
    </figure>
  )
}

<NotionRenderer blocks={blocks} components={{ image: NextImage }} />
```

# Video

**In Notion:** type `/video`, then paste a YouTube link or upload a file.

[A YouTube video](https://www.youtube.com/watch?v=dQw4w9WgXcQ)

**Renders as:** a YouTube embed, or a `<video>` with controls for a video file.

# Audio

**In Notion:** type `/audio`, then upload a file or paste a link.

[An audio file](https://upload.wikimedia.org/wikipedia/commons/c/c8/Example.ogg)

**Renders as:** an `<audio>` with the browser's controls.

# File

**In Notion:** type `/file`, then upload a file or paste a link.

[dummy.pdf](https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf)

**Renders as:** a card with the file's name and type, linking to it, and the caption below.

```typescript
// Customize · file.tsx
import { resolveFileUrl, type BlockProps } from "notionic"

export function DownloadFile({ block, context }: BlockProps<"file">) {
  const url = resolveFileUrl(block.file, block.id, context)
  if (!url) return null
  return (
    <a href={url} download className="inline-flex rounded-md border border-border px-3 py-2 text-sm">
      Download {block.file.name ?? "file"}
    </a>
  )
}

<NotionRenderer blocks={blocks} components={{ file: DownloadFile }} />
```

# PDF

**In Notion:** type `/pdf`, then upload a file or paste a link.

[A PDF](https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf)

**Renders as:** a card like a file's, linking to the PDF.
