---
title: "Extensions"
description: "Add SSE, WebSockets, file downloads, and more."
thumbnail: "docs/extensions.svg"
---

import { getFolder } from '../../lib/content';
import { EXTENSION_CATEGORIES, groupFilesByCategory } from '../../lib/content-groups';
import JumpTo from '../../components/JumpTo.astro';

export const folder = await getFolder('extensions');
export const grouped = groupFilesByCategory(folder.files, EXTENSION_CATEGORIES).map(group => ({
    category: group.category,
    slug: group.slug,
    items: group.files.map(f => ({
        title: f.frontmatter.title,
        url: f.url,
        descriptionParts: f.frontmatter.description?.split(/(`[^`]+`)/g),
        icon: f.frontmatter.icon,
    })),
}));

export const getPageHeadings = () => grouped.map(group => ({
    depth: 2,
    slug: group.slug,
    text: group.category,
}));

<label data-active-search class="not-prose text-field" for="extensions-search">
    <span class="sr-only">Search extensions</span>
    <i class="icon-[mdi--magnify]" aria-hidden="true"></i>
    <input
        id="extensions-search"
        type="text"
        placeholder="Search extensions..."
        autocomplete="off"
        autocapitalize="off"
        autocorrect="off"
        spellcheck="false"
        enterkeyhint="search"
        aria-keyshortcuts="/"
        _="install ActiveSearch"
    />
    <span aria-hidden="true">Focus <kbd>/</kbd></span>
</label>

<JumpTo headings={getPageHeadings()} />

{grouped.map(group => (
<section role="group">

<h2 id={group.slug}>
    <span>
        <a href={`#${group.slug}`} class="no-underline interact:underline">
            {group.category}
        </a>
    </span>
</h2>

<table>
    <tbody>
        {group.items.map(item => (
            <tr class="stretch-link">
                <td>
                    <div class="grid grid-cols-[1.25rem_minmax(0,1fr)] sm:grid-cols-[1.25rem_12rem_minmax(0,1fr)] gap-x-5 items-center">
                        {item.icon ? <i class={`${item.icon} size-5 row-span-2 sm:row-span-1 self-start sm:self-center mt-1 sm:mt-0`}></i> : <span></span>}
                        <a href={item.url}><code>{item.title}</code></a>
                        <span class="col-start-2 sm:col-start-3 sm:row-start-1 text-[0.8125em] sm:text-[1em] text-neutral-650 dark:text-neutral-350 mt-0.5 sm:mt-0">{item.descriptionParts?.map(part => part.startsWith('`') ? <code>{part.slice(1, -1)}</code> : part)}</span>
                    </div>
                </td>
            </tr>
        ))}
    </tbody>
</table>

</section>
))}
