Skip to content

v0.4.0 Per custom item components, tab position, items sorting

Choose a tag to compare

@VeiaG VeiaG released this 22 Jun 17:37
· 8 commits to main since this release
964b42a

Summary of changes

Three additive, opt-in features for the sidebar. All changes are backwards compatible — existing configs render exactly as before.


1. Per-item custom component (customItems[].component)

A customItems entry can now render your own component in the nav row instead of a default link. The component is rendered through Payload's component system, so both server and client components are supported, and it's registered in the import map automatically.

customItems: [
  {
    slug: 'storage-meter',
    component: './components/Sidebar#StorageMeter', // or { path, clientProps }
    position: 'top',   // honors the same group/position rules as link items
    group: 'Content',
  },
  // regular link items keep working alongside it
  { slug: 'drafts', href: '/collections/posts?status=draft', label: 'Drafts' },
]
  • Props are deliberately minimal — the component receives CustomNavItemComponentProps ({ slug }) plus any clientProps. For rich, shared link rendering use customComponents.NavItem instead.
  • Supports the same group / position placement as link items. When merged into an existing group, it is appended to the bottom of that group (same as link items).
  • Access control (access) works the same as link items.

New exported type: CustomNavItemComponentProps.


2. Per-tab ordering (sort)

A new top-level sort option gives full control over the order of groups and items per tab, applied as a final pass over the default ordering. Tabs not listed are untouched.

payloadEnhancedSidebar({
  sort: {
    // keyed by tab id
    shop: {
      // orders the top-level groups within the tab
      groups: (group, ctx) => {
        if (group.isUngrouped && group.entities[0]?.slug === 'banner') return -100
        if (typeof group.label !== 'string' && group.label.en === 'Featured') return 0
      },
      // orders the entities inside each group
      items: (item, group, ctx) => {
        if (item.type === 'custom-component') return 10 // place after collections
        if (item.slug === 'products') return -10        // pin products first
      },
    },
  },
})

Sort key semantics (like CSS order):

  • number — explicit order index; lower comes first.
  • string — sorted lexicographically (localeCompare).
  • undefined — treated as 0, i.e. keeps the default position.
  • Sorting is stable — anything you don't assign a key to keeps its default position. Avoid mixing numbers and strings in the same scope (numbers sort before strings).

Notes:

  • Group/entity labels are passed raw (not translated) — branch on group.label.en etc., or translate via ctx.locale.
  • items sorts only within a group — it cannot move an item to another group (use group for that).
  • When groups is set, ungrouped items become individual single-item units, so you can interleave them between real groups (e.g. a banner above one group, a CTA below another). This is visually a no-op for the default rendering.
  • sort is a final pass and overrides customItems position.
  • The tab bar order (icons on the left) is unaffected — that's simply the order of the tabs array.

New exported types: TabSortConfig, GroupSortFunction, ItemSortFunction, SortableGroup, SidebarSortKey, SidebarSortContext (plus ExtendedEntity, ExtendedGroup).


3. Tab bar position

Any tab, link, or custom slot can now be pinned to the bottom of the tabs bar — just above the actions area (folders / settings / logout) — via position: 'bottom' (default 'top').

tabs: [
  { id: 'dashboard', type: 'link', href: '/', icon: 'House', label: 'Dashboard' },
  { id: 'content', type: 'tab', icon: 'FileText', label: 'Content', collections: ['posts'] },
  // pinned to the bottom, above the logout button
  { id: 'settings', type: 'tab', icon: 'Settings', label: 'Settings', globals: ['site-settings'], position: 'bottom' },
]
  • Bottom items render in config order, grouped together just above the actions.
  • Known limitation: the tab bar is not scrollable/virtualized — position is intended for a small number of pinned items (settings, help, etc.). A large number of top tabs may collide with the bottom group.

Full Changelog: v0.3.3...v0.4.0