Menu

Change language

GitHub repo

Dual-Rail Sidebar

blocklayout

Dual-rail sidebar -- a thin always-visible icon column on the far left holds quick shortcuts (a subset of the full nav), paired with a wider main panel for the brand, search, sections, and footer. Uses collapsible="icon": when the user collapses, only the rail stays. On mobile the kit Sheet shows the full dual rail. Requires the parent SidebarProvider to set both widths: style={{ '--sidebar-width': '19.5rem', '--sidebar-width-icon': '3.5rem' }}. Modeled on the GR8R HRMS admin shell.

Installation

$npx shadcn@latest add https://uipkge.dev/r/lit/sidebar-05.json
Manifest:https://uipkge.dev/r/lit/sidebar-05.jsonInstalls to:src/uip/blocks/sidebar-05/

Variants

Loading interactive previews…

Schema

Type aliases exported from this item's source. Use these to shape the data you pass in.

HTMLElementTagNameMap
interface HTMLElementTagNameMap {
    'uip-sidebar-05': UipSidebar05
  }
}

Files installed (1)

  • src/uip/blocks/sidebar-05/sidebar-05.ts25.8 kB
    import { LitElement, css, html, nothing } from 'lit'
    import {
      Bell,
      Briefcase,
      Calendar,
      ChartLine,
      ChevronsUpDown,
      ClipboardList,
      CreditCard,
      FileText,
      Folder,
      Gauge,
      Headphones,
      HelpCircle,
      Home,
      Inbox,
      LayoutDashboard,
      Lock,
      Mail,
      MessageSquare,
      Moon,
      Search,
      Send,
      Settings as SettingsIcon,
      Star,
      Sun,
      Users,
    } from 'lucide'
    import { tailwind } from '../../lib/styles'
    import { ThemeController } from '../../lib/theme'
    import { icon } from '../../lib/icon'
    // Side-effect imports: register the composed elements for standalone use
    // (consumers who install only this block still get working primitives).
    import '../../components/avatar/avatar'
    import '../../components/dropdown-menu/dropdown-menu'
    import '../../components/input/input'
    import type { UipInput } from '../../components/input/input'
    import '../../components/sidebar/sidebar'
    import type { UipSidebarProvider } from '../../components/sidebar/sidebar'
    
    type RailId = 'home' | 'projects' | 'inbox' | 'messages' | 'support' | 'settings'
    
    const rail = [
      { id: 'home' as const, icon: Home, iconName: 'house', label: 'Home' },
      { id: 'projects' as const, icon: Folder, iconName: 'folder', label: 'Projects' },
      { id: 'inbox' as const, icon: Bell, iconName: 'bell', label: 'Inbox' },
      { id: 'messages' as const, icon: MessageSquare, iconName: 'message-square', label: 'Messages' },
    ]
    const railLower = [
      { id: 'support' as const, icon: Headphones, iconName: 'headphones', label: 'Support' },
      { id: 'settings' as const, icon: SettingsIcon, iconName: 'settings', label: 'Settings' },
    ]
    
    const titles: Record<RailId, string> = {
      home: 'Workspace',
      projects: 'Projects',
      inbox: 'Inbox',
      messages: 'Messages',
      support: 'Support',
      settings: 'Settings',
    }
    
    function isDarkActive(): boolean {
      return document.documentElement.classList.contains('dark')
    }
    
    function setDark(dark: boolean) {
      document.documentElement.classList.toggle('dark', dark)
      try {
        localStorage.setItem('uipkge-theme', dark ? 'dark' : 'light')
      } catch {
        // ignore
      }
    }
    
    function brandMark(classes: string) {
      return html`<svg viewBox="0 0 24 24" class=${classes} fill="currentColor" aria-hidden="true">
        <rect x="2" y="2" width="9" height="9" rx="1.5" />
        <rect x="13" y="2" width="9" height="9" rx="1.5" opacity="0.55" />
        <rect x="2" y="13" width="9" height="9" rx="1.5" opacity="0.55" />
        <rect x="13" y="13" width="9" height="9" rx="1.5" />
      </svg>`
    }
    
    // Dual-rail sidebar with master/detail behavior. The thin rail picks the
    // section; the main panel renders the rows for the active section. One
    // <uip-sidebar collapsible="icon"> contains rail + panel as inline flex siblings.
    //
    // Desktop: when collapsed (toggle clicked), the kit shrinks the sidebar to
    // --sidebar-width-icon. The panel hides via group-data-[collapsible=icon];
    // the mobile sheet always shows rail+panel.
    //
    // IMPORTANT: the parent <uip-sidebar-provider> must set BOTH custom widths,
    // e.g. style="--sidebar-width: 19.5rem; --sidebar-width-icon: 3.5rem".
    // To wire to your router, replace the state-based switch with route matches
    // (e.g. set active = 'projects' on /projects/*).
    
    /**
     * <uip-sidebar-05> — the registry Sidebar05 block as a web component.
     *
     * Class strings are React's verbatim. Rail clicks use the surrounding
     * <uip-sidebar-provider> (state / setOpen / isMobile — React's useSidebar);
     * the block re-renders when the provider's `open-change` fires. The search
     * field is <uip-input> with `prefix`/`suffix` slots (React's SidebarInput
     * prefix/suffix props). The theme toggle writes the `dark` class on
     * documentElement directly (the `next-themes` dependency is not ported).
     * No props, no events: edit the markup in place.
     */
    export class UipSidebar05 extends LitElement {
      static shadowRootOptions = { ...LitElement.shadowRootOptions, delegatesFocus: true }
      // :host display can't be a utility class (the host has no template of its own).
      static styles = [tailwind, css`:host { display: block; }`]
    
      static properties = {
        active: { state: true },
        isDark: { state: true },
        query: { state: true },
      }
    
      private active: RailId = 'home'
      private isDark = false
      private query = ''
      private media?: MediaQueryList
    
      constructor() {
        super()
        new ThemeController(this)
      }
    
      connectedCallback() {
        super.connectedCallback()
        this.setAttribute('data-uipkge', '')
        this.setAttribute('data-slot', 'sidebar-05')
        this.isDark = isDarkActive()
        // Re-render when the provider opens/closes or the viewport crosses the
        // mobile breakpoint (React's useSidebar re-render).
        this.addEventListener('open-change', this.rerender)
        this.media = window.matchMedia('(max-width: 768px)')
        this.media.addEventListener('change', this.rerender)
      }
    
      disconnectedCallback() {
        super.disconnectedCallback()
        this.removeEventListener('open-change', this.rerender)
        this.media?.removeEventListener('change', this.rerender)
      }
    
      private rerender = () => this.requestUpdate()
    
      private get provider(): UipSidebarProvider | null {
        const p = this.closest('uip-sidebar-provider')
        return (p as UipSidebarProvider | null) ?? null
      }
    
      // Slack-style rail click: expand the panel if collapsed, or collapse if
      // the user clicks the already-active icon while expanded. On mobile the
      // sheet open/close is owned by the inset trigger, so we just swap active.
      private selectRail(id: RailId) {
        const provider = this.provider
        if (provider?.isMobile) {
          this.active = id
          return
        }
        if (provider && provider.state === 'expanded' && this.active === id) {
          provider.setOpen(false)
          return
        }
        this.active = id
        provider?.setOpen(true)
      }
    
      private railButton(item: { id: RailId; icon: typeof Home; iconName: string; label: string }) {
        return html`
          <button
            type="button"
            aria-label=${item.label}
            aria-current=${this.active === item.id ? 'page' : nothing}
            class=${[
              'relative flex aspect-square size-9 items-center justify-center rounded-lg transition-colors',
              this.active === item.id
                ? 'bg-sidebar-accent text-foreground'
                : 'text-muted-foreground hover:bg-sidebar-accent/60 hover:text-foreground',
            ].join(' ')}
            @click=${() => this.selectRail(item.id)}
          >
            ${this.active === item.id
              ? html`<span class="bg-sidebar-primary absolute top-1/2 left-0 h-5 w-0.5 -translate-y-1/2 rounded-r-full"></span>`
              : ''}
            ${icon(item.icon, item.iconName, 'size-4')}
          </button>
        `
      }
    
      render() {
        const isMobile = this.provider?.isMobile ?? false
        return html`
          <uip-sidebar collapsible="icon">
            <div class="flex h-full w-full">
              <aside class="border-sidebar-border flex w-14 shrink-0 flex-col items-center gap-0.5 border-r py-2">
                <button
                  type="button"
                  aria-label="uipkge"
                  class="bg-sidebar-primary text-sidebar-primary-foreground mb-1 flex aspect-square size-9 items-center justify-center rounded-lg shadow-sm ring-1 ring-white/10 transition-transform ring-inset hover:scale-105"
                >
                  ${brandMark('size-4')}
                </button>
    
                ${rail.map((item) => this.railButton(item))}
    
                <div class="bg-sidebar-border/70 my-2 h-px w-7"></div>
    
                ${railLower.map((item) => this.railButton(item))}
    
                <div class="mt-auto flex flex-col items-center gap-1.5">
                  <button
                    type="button"
                    aria-label=${this.isDark ? 'Switch to light theme' : 'Switch to dark theme'}
                    class="text-muted-foreground hover:bg-sidebar-accent/60 hover:text-foreground flex aspect-square size-9 items-center justify-center rounded-lg transition-colors"
                    @click=${() => {
                      this.isDark = !this.isDark
                      setDark(this.isDark)
                    }}
                  >
                    ${this.isDark ? icon(Sun, 'sun', 'size-4') : icon(Moon, 'moon', 'size-4')}
                  </button>
    
                  <uip-dropdown-menu class="[&::part(content)]:min-w-56 [&::part(content)]:rounded-lg">
                    <button
                      slot="trigger"
                      type="button"
                      aria-label="James Carter"
                      class="ring-offset-sidebar focus-visible:ring-ring data-[state=open]:ring-ring rounded-full transition focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none data-[state=open]:ring-2"
                    >
                      <uip-avatar class="size-8">
                        <uip-avatar-fallback class="bg-sidebar-accent text-sidebar-accent-foreground text-xs">JC</uip-avatar-fallback>
                      </uip-avatar>
                    </button>
                    <uip-dropdown-menu-content side=${isMobile ? 'top' : 'right'} align="end" side-offset="8">
                      <uip-dropdown-menu-label>
                        <div class="flex items-center gap-2 px-1 py-1.5 text-left text-sm">
                          <uip-avatar class="size-8 rounded-lg">
                            <uip-avatar-fallback class="bg-sidebar-accent text-sidebar-accent-foreground rounded-lg text-xs">JC</uip-avatar-fallback>
                          </uip-avatar>
                          <div class="grid flex-1 leading-tight">
                            <span class="truncate font-medium">James Carter</span>
                            <span class="text-muted-foreground truncate text-xs">Admin</span>
                          </div>
                        </div>
                      </uip-dropdown-menu-label>
                      <uip-dropdown-menu-separator></uip-dropdown-menu-separator>
                      <uip-dropdown-menu-item>${icon(Send, 'send', 'size-4')} Invite teammates</uip-dropdown-menu-item>
                      <uip-dropdown-menu-item>${icon(SettingsIcon, 'settings', 'size-4')} Workspace settings</uip-dropdown-menu-item>
                    </uip-dropdown-menu-content>
                  </uip-dropdown-menu>
                </div>
              </aside>
    
              <div class="flex min-w-0 flex-1 flex-col group-data-[collapsible=icon]:hidden">
                <uip-sidebar-header>
                  <uip-sidebar-menu>
                    <uip-sidebar-menu-item>
                      <uip-sidebar-menu-button size="lg">
                        <div class="bg-sidebar-primary text-sidebar-primary-foreground flex aspect-square size-8 shrink-0 items-center justify-center rounded-lg">
                          ${brandMark('size-4')}
                        </div>
                        <div class="grid flex-1 text-left text-sm leading-tight">
                          <span class="font-display truncate font-bold">uipkge</span>
                          <span class="text-muted-foreground truncate text-xs">${titles[this.active]}</span>
                        </div>
                        ${icon(ChevronsUpDown, 'chevrons-up-down', 'ml-auto size-4')}
                      </uip-sidebar-menu-button>
                    </uip-sidebar-menu-item>
                  </uip-sidebar-menu>
    
                  <div class="px-1 pt-1">
                    <uip-input
                      type="text"
                      placeholder="Search..."
                      allow-clear
                      class="[&::part(control)]:bg-background [&::part(control)]:h-8 [&::part(control)]:shadow-none"
                      .value=${this.query}
                      @input=${(e: Event) => {
                        this.query = (e.target as UipInput).value
                      }}
                    >
                      <span slot="prefix">${icon(Search, 'search', 'size-3.5')}</span>
                      <kbd slot="suffix" class="bg-muted text-muted-foreground pointer-events-none inline-flex h-5 items-center gap-0.5 rounded border px-1 font-mono text-xs font-medium select-none">
                        <span>&#8984;</span>F
                      </kbd>
                    </uip-input>
                  </div>
                </uip-sidebar-header>
    
                <uip-sidebar-content>
                  ${this.active === 'home'
                    ? html`
                        <uip-sidebar-group>
                          <uip-sidebar-group-content>
                            <uip-sidebar-menu>
                              <uip-sidebar-menu-item>
                                <uip-sidebar-menu-button is-active>
                                  ${icon(LayoutDashboard, 'layout-dashboard', 'size-4')} <span>Dashboard</span>
                                </uip-sidebar-menu-button>
                              </uip-sidebar-menu-item>
                              <uip-sidebar-menu-item>
                                <uip-sidebar-menu-button>
                                  ${icon(Users, 'users', 'size-4')} <span>Employees</span>
                                </uip-sidebar-menu-button>
                              </uip-sidebar-menu-item>
                              <uip-sidebar-menu-item>
                                <uip-sidebar-menu-button>
                                  ${icon(Briefcase, 'briefcase', 'size-4')} <span>Clients</span>
                                </uip-sidebar-menu-button>
                              </uip-sidebar-menu-item>
                              <uip-sidebar-menu-item>
                                <uip-sidebar-menu-button>
                                  ${icon(Folder, 'folder', 'size-4')} <span>Projects</span>
                                </uip-sidebar-menu-button>
                              </uip-sidebar-menu-item>
                            </uip-sidebar-menu>
                          </uip-sidebar-group-content>
                        </uip-sidebar-group>
    
                        <uip-sidebar-group>
                          <uip-sidebar-group-label>Workforce</uip-sidebar-group-label>
                          <uip-sidebar-group-content>
                            <uip-sidebar-menu>
                              <uip-sidebar-menu-item>
                                <uip-sidebar-menu-button>
                                  ${icon(Calendar, 'calendar', 'size-4')} <span>Calendar</span>
                                </uip-sidebar-menu-button>
                              </uip-sidebar-menu-item>
                              <uip-sidebar-menu-item>
                                <uip-sidebar-menu-button>
                                  ${icon(ClipboardList, 'clipboard-list', 'size-4')} <span>Attendance</span>
                                </uip-sidebar-menu-button>
                              </uip-sidebar-menu-item>
                              <uip-sidebar-menu-item>
                                <uip-sidebar-menu-button>
                                  ${icon(Mail, 'mail', 'size-4')} <span>Mail</span>
                                </uip-sidebar-menu-button>
                              </uip-sidebar-menu-item>
                              <uip-sidebar-menu-item>
                                <uip-sidebar-menu-button>
                                  ${icon(ChartLine, 'chart-line', 'size-4')} <span>Analytics</span>
                                </uip-sidebar-menu-button>
                              </uip-sidebar-menu-item>
                            </uip-sidebar-menu>
                          </uip-sidebar-group-content>
                        </uip-sidebar-group>
                      `
                    : ''}
                  ${this.active === 'projects'
                    ? html`
                        <uip-sidebar-group>
                          <uip-sidebar-group-label>Pinned</uip-sidebar-group-label>
                          <uip-sidebar-group-content>
                            <uip-sidebar-menu>
                              ${[
                                { tile: 'bg-chart-1', name: 'Shift Planner' },
                                { tile: 'bg-chart-2', name: 'Training Portal' },
                                { tile: 'bg-chart-3', name: 'Performance Hub' },
                                { tile: 'bg-chart-4', name: 'Expense Claims' },
                              ].map(
                                (p) => html`
                                  <uip-sidebar-menu-item>
                                    <uip-sidebar-menu-button>
                                      <div class=${`${p.tile} flex aspect-square size-5 shrink-0 items-center justify-center rounded-md text-white`}>
                                        ${icon(Folder, 'folder', 'size-3')}
                                      </div>
                                      <span>${p.name}</span>
                                      ${icon(Star, 'star', 'text-warning ml-auto size-3.5 fill-current')}
                                    </uip-sidebar-menu-button>
                                  </uip-sidebar-menu-item>
                                `,
                              )}
                            </uip-sidebar-menu>
                          </uip-sidebar-group-content>
                        </uip-sidebar-group>
    
                        <uip-sidebar-group>
                          <uip-sidebar-group-label>Recent</uip-sidebar-group-label>
                          <uip-sidebar-group-content>
                            <uip-sidebar-menu>
                              ${['Onboarding 2026', 'Q1 hiring plan', 'Compliance refresh'].map(
                                (name) => html`
                                  <uip-sidebar-menu-item>
                                    <uip-sidebar-menu-button>
                                      ${icon(Folder, 'folder', 'size-4')} <span>${name}</span>
                                    </uip-sidebar-menu-button>
                                  </uip-sidebar-menu-item>
                                `,
                              )}
                            </uip-sidebar-menu>
                          </uip-sidebar-group-content>
                        </uip-sidebar-group>
                      `
                    : ''}
                  ${this.active === 'inbox'
                    ? html`
                        <uip-sidebar-group>
                          <uip-sidebar-group-label>Today</uip-sidebar-group-label>
                          <uip-sidebar-group-content>
                            <uip-sidebar-menu>
                              <uip-sidebar-menu-item>
                                <uip-sidebar-menu-button>
                                  ${icon(Inbox, 'inbox', 'size-4')} <span>3 PTO requests pending</span>
                                </uip-sidebar-menu-button>
                              </uip-sidebar-menu-item>
                              <uip-sidebar-menu-item>
                                <uip-sidebar-menu-button>
                                  ${icon(Bell, 'bell', 'size-4')} <span>Payroll cycle closes today</span>
                                </uip-sidebar-menu-button>
                              </uip-sidebar-menu-item>
                            </uip-sidebar-menu>
                          </uip-sidebar-group-content>
                        </uip-sidebar-group>
    
                        <uip-sidebar-group>
                          <uip-sidebar-group-label>This week</uip-sidebar-group-label>
                          <uip-sidebar-group-content>
                            <uip-sidebar-menu>
                              <uip-sidebar-menu-item>
                                <uip-sidebar-menu-button>
                                  ${icon(FileText, 'file-text', 'size-4')} <span>5 contracts awaiting sign-off</span>
                                </uip-sidebar-menu-button>
                              </uip-sidebar-menu-item>
                              <uip-sidebar-menu-item>
                                <uip-sidebar-menu-button>
                                  ${icon(Users, 'users', 'size-4')} <span>2 new hires start Monday</span>
                                </uip-sidebar-menu-button>
                              </uip-sidebar-menu-item>
                            </uip-sidebar-menu>
                          </uip-sidebar-group-content>
                        </uip-sidebar-group>
                      `
                    : ''}
                  ${this.active === 'messages'
                    ? html`
                        <uip-sidebar-group>
                          <uip-sidebar-group-label>Direct messages</uip-sidebar-group-label>
                          <uip-sidebar-group-content>
                            <uip-sidebar-menu>
                              ${[
                                { initials: 'OB', tile: 'bg-chart-1/15', name: 'Olivia Bennett' },
                                { initials: 'DM', tile: 'bg-chart-2/15', name: 'Daniel Morgan' },
                                { initials: 'ER', tile: 'bg-chart-3/15', name: 'Ethan Reynolds' },
                              ].map(
                                (person) => html`
                                  <uip-sidebar-menu-item>
                                    <uip-sidebar-menu-button>
                                      <uip-avatar class="size-5">
                                        <uip-avatar-fallback class=${`${person.tile} text-foreground text-xs`}>${person.initials}</uip-avatar-fallback>
                                      </uip-avatar>
                                      <span>${person.name}</span>
                                    </uip-sidebar-menu-button>
                                  </uip-sidebar-menu-item>
                                `,
                              )}
                            </uip-sidebar-menu>
                          </uip-sidebar-group-content>
                        </uip-sidebar-group>
    
                        <uip-sidebar-group>
                          <uip-sidebar-group-label>Channels</uip-sidebar-group-label>
                          <uip-sidebar-group-content>
                            <uip-sidebar-menu>
                              <uip-sidebar-menu-item>
                                <uip-sidebar-menu-button>
                                  ${icon(MessageSquare, 'message-square', 'size-4')} <span># announcements</span>
                                </uip-sidebar-menu-button>
                              </uip-sidebar-menu-item>
                              <uip-sidebar-menu-item>
                                <uip-sidebar-menu-button>
                                  ${icon(MessageSquare, 'message-square', 'size-4')} <span># hiring</span>
                                </uip-sidebar-menu-button>
                              </uip-sidebar-menu-item>
                            </uip-sidebar-menu>
                          </uip-sidebar-group-content>
                        </uip-sidebar-group>
                      `
                    : ''}
                  ${this.active === 'support'
                    ? html`
                        <uip-sidebar-group>
                          <uip-sidebar-group-label>Help center</uip-sidebar-group-label>
                          <uip-sidebar-group-content>
                            <uip-sidebar-menu>
                              <uip-sidebar-menu-item>
                                <uip-sidebar-menu-button>
                                  ${icon(HelpCircle, 'circle-question-mark', 'size-4')} <span>Getting started</span>
                                </uip-sidebar-menu-button>
                              </uip-sidebar-menu-item>
                              <uip-sidebar-menu-item>
                                <uip-sidebar-menu-button>
                                  ${icon(FileText, 'file-text', 'size-4')} <span>Onboarding guide</span>
                                </uip-sidebar-menu-button>
                              </uip-sidebar-menu-item>
                              <uip-sidebar-menu-item>
                                <uip-sidebar-menu-button>
                                  ${icon(Send, 'send', 'size-4')} <span>Contact support</span>
                                </uip-sidebar-menu-button>
                              </uip-sidebar-menu-item>
                            </uip-sidebar-menu>
                          </uip-sidebar-group-content>
                        </uip-sidebar-group>
                      `
                    : ''}
                  ${this.active === 'settings'
                    ? html`
                        <uip-sidebar-group>
                          <uip-sidebar-group-label>Workspace</uip-sidebar-group-label>
                          <uip-sidebar-group-content>
                            <uip-sidebar-menu>
                              <uip-sidebar-menu-item>
                                <uip-sidebar-menu-button>
                                  ${icon(SettingsIcon, 'settings', 'size-4')} <span>General</span>
                                </uip-sidebar-menu-button>
                              </uip-sidebar-menu-item>
                              <uip-sidebar-menu-item>
                                <uip-sidebar-menu-button>
                                  ${icon(Users, 'users', 'size-4')} <span>Members</span>
                                </uip-sidebar-menu-button>
                              </uip-sidebar-menu-item>
                              <uip-sidebar-menu-item>
                                <uip-sidebar-menu-button>
                                  ${icon(CreditCard, 'credit-card', 'size-4')} <span>Billing</span>
                                </uip-sidebar-menu-button>
                              </uip-sidebar-menu-item>
                              <uip-sidebar-menu-item>
                                <uip-sidebar-menu-button>
                                  ${icon(Gauge, 'gauge', 'size-4')} <span>Limits</span>
                                </uip-sidebar-menu-button>
                              </uip-sidebar-menu-item>
                            </uip-sidebar-menu>
                          </uip-sidebar-group-content>
                        </uip-sidebar-group>
    
                        <uip-sidebar-group>
                          <uip-sidebar-group-label>Account</uip-sidebar-group-label>
                          <uip-sidebar-group-content>
                            <uip-sidebar-menu>
                              <uip-sidebar-menu-item>
                                <uip-sidebar-menu-button>
                                  ${icon(Lock, 'lock', 'size-4')} <span>Security</span>
                                </uip-sidebar-menu-button>
                              </uip-sidebar-menu-item>
                              <uip-sidebar-menu-item>
                                <uip-sidebar-menu-button>
                                  ${icon(Bell, 'bell', 'size-4')} <span>Notifications</span>
                                </uip-sidebar-menu-button>
                              </uip-sidebar-menu-item>
                            </uip-sidebar-menu>
                          </uip-sidebar-group-content>
                        </uip-sidebar-group>
                      `
                    : ''}
                </uip-sidebar-content>
              </div>
            </div>
          </uip-sidebar>
        `
      }
    }
    
    customElements.get('uip-sidebar-05') || customElements.define('uip-sidebar-05', UipSidebar05)
    
    declare global {
      interface HTMLElementTagNameMap {
        'uip-sidebar-05': UipSidebar05
      }
    }
    

Raw manifest:https://uipkge.dev/r/lit/sidebar-05.json