Skip to content
HomePagesHomePages template kit

Add a third-party package

Use a third-party npm package in a section.

Use an npm package in a section.

Install the package like any npm dependency:

Terminal window
npm i swiper

Only a published version. pack refuses to produce a submission zip when a dependency uses a local file:/link: protocol — depend on a real published version, never a path on your own machine.

Where you import it from matters. A client library — a carousel, a map SDK, anything that touches window or the DOM — is imported inside a "use client" island, the same as any other browser-only code:

sections/gallery/Carousel.tsx
"use client";
import Swiper from "swiper";
export default function Carousel({ slides }: { slides: { id: string; url: string }[] }) {
// …
}

A server-side import — one that lands in the Renderer or a plain component it imports, not behind "use client" — must stay pure and deterministic: no reads of the clock, randomness, or the network at render time. A package built for a browser runtime (it touches window, schedules a timer, generates an id) does not belong there; move the usage into an island.

A package that ships its own stylesheet is imported by its bare specifier, from the module that renders it — the Renderer’s import graph (the components and islands it imports, transitively) is what the CSS build bundles and harvests for the section’s stylesheet:

sections/gallery/Carousel.tsx
"use client";
import Swiper from "swiper";
import "swiper/css"; // ← the sanctioned channel: a bare specifier reaches this section's layer

A local .css import from that same render path is a different, banned case — see no-css-import-from-render-path for the full distinction between the two, and no-bare-css-import for why a hand-written stylesheet can’t reach the package’s CSS with its own @import instead.

The install and the fences under Steps — the import inside a "use client" island, and the package’s own stylesheet by its bare specifier — are the whole change.

Verify with the author loop — a green check after the install confirms the package resolves, its CSS (if any) landed in the section’s layer, and the workspace still carries exactly one copy of React.

  • single-react — the package pulls in its own copy of react or react-dom.
  • audit-severity — the package carries a high or critical security advisory.
  • no-client-runtime-in-server — the import lands on the render path and the package reaches for state, an effect, or a browser global.
  • no-nondeterminism — the same import reads the clock or generates randomness at render time.
  • no-css-import-from-render-path — you reach the package’s stylesheet through a local .css import instead of its bare specifier.
  • no-bare-css-import — you reach it through an @import in a hand-written stylesheet instead.
  • size-island-bundle — the package lands in an island and pushes that section’s browser bundle past its byte budget.
  • Islands — writing a "use client" island; a third-party client library is fine inside one, never in a Renderer.
  • template-kit pack — why a file:/link: dependency blocks a submission.
  • single-react — a package that pulls its own copy of React breaks hydration; the installed tree may carry only one.
  • no-css-import-from-render-path — bare package specifier (legal) vs. a local .css import (banned) from a section’s render path.
  • no-bare-css-import — why a hand-written stylesheet can’t reach a package’s CSS with its own @import either.