Entry points
The Payload packages straddle the server and client boundary, so each ships more than one entry. Importing from the wrong one is the most common wiring mistake. @bison-lab/admin-ui is a single entry and stays free of Payload.
@bison-lab/payload-blocks
Section titled “@bison-lab/payload-blocks”| Import | Contents | Runs where |
|---|---|---|
@bison-lab/payload-blocks |
Block configs, field builders, row types, resolveMedia, orphanBlockTypes, blockSamples, sampleImage, lookField, colorTokenField |
Node. What payload.config.ts imports. Touches no React. |
@bison-lab/payload-blocks/hooks |
Collection hooks a site adds itself: saveFaqsToLibrary |
Server. Imports Payload’s error classes as values, so only payload.config.ts and its collections import it; the main entry stays safe for a client component to reach. |
@bison-lab/payload-blocks/react |
Renderers, RenderBlocks and BLOCK_ID_ATTRIBUTE, the image and link seams, resolveLink and ResolveLink, headerFromNavigation, headerItemsFromBlocks, the seam constants, the rendering types |
Client ("use client"). |
@bison-lab/payload-blocks/rich-text |
RichTextBlockRenderer, richTextBlockRenderer() to build one that resolves internal links, and internalDocToHrefFrom |
Client. Split out because it is the only thing that needs @payloadcms/richtext-lexical. |
@bison-lab/payload-blocks/admin |
MinRowsArrayField, ItemsField, LinkField, NavItemsField, AdminWorkspace, FooterColumnsField, the client half of SectionSettingsField |
Client, inside the Payload admin. Resolved through the site’s import map, never imported by hand. |
@bison-lab/payload-blocks/admin-server |
SectionSettingsField: the Block Settings fold, which reads the Block library with payload and hands the client fold the block’s controls |
Server, inside the Payload admin. No "use client" banner. Resolved through the import map. |
The renderers are client components because the blocks they render are: every @bison-lab/ui export is a client reference, and the blocks are interactive anyway. That is also what makes imageComponent work. A Server Component can hand a client component reference across the boundary, but not a closure.
The admin entries are referenced by string, never imported: a config names MIN_ROWS_ARRAY_FIELD, ITEMS_FIELD, LINK_FIELD, NAV_ITEMS_FIELD, ADMIN_WORKSPACE or SECTION_SETTINGS_FIELD (exported from the main entry) as a field or view component, and payload generate:importmap turns the string into the import. A missing entry renders the field as nothing, not as the stock field. SECTION_SETTINGS_FIELD points at admin-server, so a site upgrading from a release where it pointed at admin regenerates its import map.
@bison-lab/payload-core
Section titled “@bison-lab/payload-core”| Import | Contents | Runs where |
|---|---|---|
@bison-lab/payload-core |
seoPlugin, createTheme, createBrandAssets, createRoles, createFeatures, createBlockLibrary, createPages, createUsers, createMedia, createRedirects, createQuestions, createTaxonomy, facetField, createAdminNav, adminNav, createNavigation, adminOnlyApiTab, documentTitleActions, listAlign, richTextEditorFonts, predicates, noIndexField, SHARE_IMAGE_SIZE, firstImageIn, title and text helpers, import-map strings (QUESTIONS_LIST, BLOCK_LIBRARY_FIELD), types |
Node. What payload.config.ts imports; it loads the SEO plugin. |
@bison-lab/payload-core/metadata |
pageMetadata, the title helpers, the same types |
Server. What a page route imports; it does not load the plugin. |
@bison-lab/payload-core/theme |
getPublishedTheme, getPublishedIdentity, themeConfigFromDoc, themeHead, themeHeadFromDoc |
Server. What a root layout imports; it does not load the plugin or React. |
@bison-lab/payload-core/navigation |
getNavigation, the Header and Footer slugs |
Server. What a site header imports; it does not load the plugin or React. |
@bison-lab/payload-core/block-library |
getSectionControls, sectionControlsFromLibrary, SectionControls, the catalogue readers |
Server. What a page route and the Block Settings fold import; it does not load the plugin or React. |
@bison-lab/payload-core/taxonomy |
facetField, FacetEntry |
Anywhere. What a block config imports to tag content from a taxonomy; it does not load the plugin or React, so a browser bundle can take it. facetField is also on the main entry. |
@bison-lab/payload-core/block-thumbnails |
captureThumbnails, thumbnailCss, NEUTRAL_THEME, thumbnailVersion, and the bison-block-thumbnails bin |
Node, beside Playwright. What a site’s Add Block screenshot script uses; it does not load Payload or React. |
@bison-lab/payload-core/wireframe |
Deprecated: captureWireframes, wireframeSvg, and the bison-wireframes bin |
Node. Kept for one release; use ./block-thumbnails. Goes in the next major. |
@bison-lab/payload-core/admin |
Theme fields, the Roles and Features matrices, BlockLibraryField, Admin nav, slug, Users Roles checklist, LookField, QuestionsList, MediaListView, MediaAltAutofill |
Admin. Referenced by import-map string; generate:importmap writes it. |
@bison-lab/payload-core/react |
ThemePreview (legacy; Theme has no preview pane) |
Client. Kept so an older site import does not break. |
@bison-lab/tokens
Section titled “@bison-lab/tokens”| Import | Contents | Runs where |
|---|---|---|
@bison-lab/tokens |
ThemeConfig and buildThemeCss, the palette derivation (deriveLightPalette, deriveDarkPalette), colour scales, the contrast audit (auditTheme), and the preset catalogues |
Anywhere. No React, no DOM. |
@bison-lab/tokens/dom |
attachEdgeShade, edgeShadeFractions and the shade custom-property names |
Browser. Framework-free DOM helpers only — no React, no Tailwind, nothing theme-derived. |
The css/* subpaths ship the stylesheets themselves (css/globals.css, css/base.css, css/themes/*, css/animations.css, css/utilities.css).
/dom is split off so @bison-lab/admin-ui can share a helper without reaching the palette derivation on the main entry: the visitor library and the admin kit deliberately do not share brand tokens. It is what keeps a pinned column’s scroll shade identical in both — @bison-lab/ui’s Table and the kit’s Table compute it from the same function and write the same two custom properties, then style it with their own CSS. @bison-lab/ui imports it at runtime; the kit bundles it at build time, so installing @bison-lab/admin-ui still pulls in nothing but radix-ui.
@bison-lab/admin-ui
Section titled “@bison-lab/admin-ui”| Import | Contents | Runs where |
|---|---|---|
@bison-lab/admin-ui |
KitProvider, type cards, dialog, confirm, Popover, Chip, ActionMenu, button, badge (variant={false} skips a preset), checkbox, input, switch, textarea, stacked Field / Label, Kicker, Fold, Stack, select, Table (pin / shade on cells), Thumbnail, Dropzone, Pagination, rail glyphs (Glyph variants or variant={false}), workspace chrome (Page for replaced lists, Canvas, ItemRail, MainHead, RailSlot) |
Client. Payload-free. Wrap a screen in KitProvider once. Replaced collection lists wrap Page. |
Field builders
Section titled “Field builders”The payload-blocks main entry exports the builders the configs are made of, for a site’s own blocks:
imageField({ name, required, relationTo, admin })for a single upload from the media collection.linkFields({ required, pagesCollection })for a full link:label, the destination row, andnewTab.linkField({ name })is the same as one named group.linkDestinationFields()is the destination row alone:type,pageandhref, carryingLINK_FIELDso the editor picks a published page or pastes a URL in one box.pagesCollectionpoints a page link at a collection other thanpages.resolveLink(link)andlinkTypeOf(link)read a destination the way every renderer and the picker do, so a site’s own code agrees with them on every row, including rows from before links had atype.headingFields({ required })for the eyebrow, title and description every band opens with.emptyRows(n)andMIN_ROWS_ARRAY_FIELDfor an array that opens withnrows and will not go below them.ITEMS_FIELDanditemsFieldAdmin({ title, thumbnail, meta, numbered, link, initials, layout, pair })for an array edited with the admin kit’s items list instead of Payload’s collapsible rows.lookField()andcolorTokenField({ name })read the published Theme. Options are the scales Color Settings offers page editors (Primary, Secondary, Accent, Highlight, plus every custom color) and only the included steps. Success and Destructive stay off that list. The picker isLOOK_FIELD(@bison-lab/payload-core/admin#LookField).resolveMedia(value)narrows an upload value, resolved or not, to{ src, alt, width, height }orundefined.
Generated types
Section titled “Generated types”Neither Payload package can import a site’s payload-types, so every row shape is hand-written and structural: every field optional and nullable, no index signatures. A generated title: string is assignable to title?: string | null, never the reverse. Sites pass their generated types in, as BlockRegistryFor<AnyBlock> and seoPlugin<Page>() show.