npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

payload-theme-kit

v0.1.0

Published

A Payload CMS admin theme plugin — branding, grouped sidebar nav, card-styled sections, and a modernized edit view, all via Payload's own customization points.

Readme

payload-theme-kit

Reusable branding, grouped sidebar navigation, and card-styled field sections for the Payload CMS admin panel. Payload has no official theme system — this plugin covers the common white-labeling needs (logo, brand color, grouped nav, nicer settings pages, a modernized edit view) via Payload's own supported customization points, without reimplementing any of its form, validation, or save logic.

Install

pnpm add payload-theme-kit

Peer dependencies: payload (^3.0.0), @payloadcms/ui (^3.0.0), @payloadcms/next (^3.0.0), react/react-dom (^19.0.0), next (^15.0.0 || ^16.0.0) — matching whatever your project already uses.

Usage

// payload.config.ts
import { themeKit } from "payload-theme-kit";

export default buildConfig({
  // ...
  plugins: [
    themeKit({
      branding: {
        logoText: "Acme",
        primaryColor: "#f29520",
      },
      nav: {
        groups: {
          Content: ["pages", "posts"],
          Applications: ["submissions", "leads"],
        },
      },
      cardSections: {
        settings: {
          "Basic Information": "Globe",
          "Social Links": "Share2",
        },
      },
      pageHeader: {
        settings: {
          icon: "Settings",
          title: "Site Settings",
          subtitle: "Manage global configuration",
        },
      },
      flattenArrays: {
        settings: { socialLinks: "platform" },
      },
      sidebar: {
        tagline: "Powered by Acme",
        roleLabel: "Admin",
      },
      booleanCells: {
        posts: ["isPublished"],
      },
    }),
  ],
});

Every option is independent and opt-in — nothing not explicitly configured is touched, and everything else is left as Payload's stock default.

After adding the plugin (or after adding a new option that registers a component path the first time — e.g. your first cardSections or pageHeader entry), run your app's Payload import-map generation once so that component path resolves. This is triggered automatically by @payloadcms/next's dev/build pipeline, or manually via payload generate:importmap.

Options

branding

  • logoText?: string — text logo shown in the nav and login screen.
  • logoImageUrl?: string — image logo; takes precedence over logoText.
  • primaryColor?: string — a single hex color, expanded into a full --color-success-{50..950} ramp anchored at 500 — Payload's accent color for buttons, active nav items, focus rings, and icon badges. This is the recommended way to set a brand color. Overriding a single CSS variable via cssVariables isn't enough on its own, since Payload's --theme- success-* tokens each derive from a different raw ramp stop depending on light/dark mode — a full generated ramp is the only way to get consistent theming in both modes.
  • cssVariables?: Record<string, string> — raw CSS custom property overrides, applied at :root inside the admin panel, merged on top of (and overriding individual stops from) primaryColor's generated ramp. Use Payload's real tokens directly, e.g. --color-base-900, --color-error-500, --color-warning-500 — see @payloadcms/ui/dist/scss/colors.scss in your installed version for the full list.

nav

  • groups: Record<string, string[]> — sidebar group label mapped to the collection/global slugs that belong under it. Sets each item's admin.group. Payload always renders its own default "Collections" and "Globals" groups first, ahead of any custom group — this plugin automatically pushes the default "Globals" group (in the default English locale) below all custom groups, since it's usually the least useful one to see first.

cardSections

  • Record<collectionOrGlobalSlug, Record<collapsibleFieldLabel, lucideIconName>>

    For each type: 'collapsible' field in the target collection/global whose label matches a key you provide, the plugin swaps in a custom label (icon + title) and scoped CSS that turns Payload's default collapsible into a bordered, shadowed card. Only collapsible fields are affected — deliberately not group fields, since group nests the field's data in your document (breaking existing data/consumers), while collapsible is UI-only. Icon names are lucide-react PascalCase export names (e.g. "Globe", "Share2") — resolved at runtime via lucide-react/dynamic.

pageHeader

  • Record<globalSlug, { icon: string; title: string; subtitle?: string }>

    Replaces a global's default plain-text title with an icon badge + title + optional subtitle banner, rendered in Payload's own admin.components.elements.Description slot right below the (now hidden) default title. Collections aren't supported — they don't have a fixed single title to replace the same way. Icon names use the same lucide-react convention as cardSections.

flattenArrays

  • Record<collectionOrGlobalSlug, Record<arrayFieldName, subFieldName>>

    Hides an array field's default header/"Collapse All" toolbar and drag handle (each row's own collapse toggle is left alone), and labels each row using the value of one of its own sub-fields instead of Payload's default "Item 01" placeholder. For example, { settings: { socialLinks: "platform" } } labels each socialLinks row with its own platform field's value.

sidebar

  • tagline?: string — small text shown under the logo in a branded panel above the nav (which becomes a clickable link to the dashboard).

  • roleLabel?: string — static label shown next to the signed-in user's email in a footer panel below the nav.

    Setting either of these registers both the brand panel and the user footer; there's currently no way to enable just one.

booleanCells

  • Record<collectionOrGlobalSlug, string[]> — checkbox field names to render as a toggle-switch pill in the collection list/table view, instead of Payload's default plain "true"/"false" text. The toggle is directly clickable there too — clicking it PATCHes the field via Payload's REST API and refreshes the row, with no need to open the document. Requires the signed-in user to have update access on the field; Payload's own access control is enforced server-side regardless of this UI.

    The edit-form checkbox input itself is always restyled as a toggle switch globally, for every checkbox field, regardless of this option — that's a pure CSS swap with no field-data risk. booleanCells is the explicit opt-in needed only for the list-view cell, since coloring it by true/false requires a custom Cell component, not just CSS.

Design notes

  • No custom edit-view replacement: Payload's per-global admin.components.views.edit slot can fully replace a global's edit view, but that means reimplementing form state, validation, save, and draft/versions UI. This plugin only swaps a field's Label/RowLabel/ Cell component and adds scoped CSS — 100% of Payload's default save/ validation path stays intact everywhere.
  • The document edit view's chrome (tabs, save button, sidebar panel, input styling, focus rings) is modernized globally via CSS, for every collection/global, with no config needed — same approach as the collection list table styling.
  • Styles are inlined as JS string constants rendered via a <style> tag inside an admin.components.providers entry, not shipped as a real .css file — so consuming Next.js apps never need to add this package to transpilePackages.