# Plugins Site-level interactive features that are not owned by a single theme component. Plugins are **optional add-ons** — a site works with none; owners turn features on in config. ## Component clients vs plugins | Concern | Mechanism | Example | |---|---|---| | Behavior owned by one component | Co-located `theme/**/*.client.js` (+ optional `.client.css`) | Gallery lightbox | | Site-wide interactive feature | `plugins` in `aftercare.config.ts` | Search, cart, forms, analytics | React in Aftercare is SSR HTML only — `onClick` does not survive the build. Client scripts bind via `data-*` hooks in the static markup. ## Built-in plugins ```ts import { search, cart, forms, googleAnalytics } from "aftercare/plugins"; export default { contentDir: "content", themeDir: "theme", publicDir: "public", outDir: "dist", plugins: [ search(), forms({ forms: { quote: { mailto: "hello@example.com", thankYouPath: "/thank-you", }, }, }), cart({ checkoutForm: "quote" }), googleAnalytics({ measurementId: "G-XXXXXXXXXX" }), ], }; ``` List `forms()` before `cart()` when checkout uses a form. | Plugin | Build output | Theme hooks | |---|---|---| | `search()` | `dist/data/search-index.json` | `data-aftercare-search-open`, `data-aftercare-search-root` | | `forms({ forms })` | `dist/data/forms-config.json` | `data-aftercare-form="id"` | | `cart({ storageKey?, checkoutForm? })` | `dist/data/cart-config.json` | `data-aftercare-add-to-cart`, `data-aftercare-cart-badge`, `data-aftercare-cart-root`, `data-aftercare-cart-checkout` | | `googleAnalytics({ measurementId })` | `dist/data/google-analytics-config.json` | _(none — injects gtag.js)_ | ### Forms Mark any form with `data-aftercare-form="id"` matching a key under `forms()`. Checkout (cart + contact fields) uses both: ```html