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

ng-hub-ui-panels

v22.1.1

Published

A versatile, accessible content-panels container for Angular with four visualizations (tabs, pills, accordion, card), standalone cards, content header/footer slots, routing, reactive forms and keyboard navigation. Part of the ng-hub-ui family.

Downloads

356

Readme

ng-hub-ui-panels

Español | English

A versatile, accessible content-panels container for Angular that renders as tabs, pills, an accordion or plain cards from a single API — with routing, reactive forms, keyboard navigation and CSS-variable theming. Built as standalone Angular components on top of Signals.

ng-hub-ui-panels supersedes ng-hub-ui-accordion. Its accordion view is a drop-in, more capable replacement.

Documentation and Live Examples

This package is part of Hub UI, a collection of Angular component libraries for standalone apps.

  • Docs: https://hubui.dev/panels/overview/
  • Live examples: https://hubui.dev/panels/examples/
  • Hub UI: https://hubui.dev/

🧩 Library Family ng-hub-ui

This library is part of the ng-hub-ui ecosystem:


🚀 Quick Start

1. Install

npm install ng-hub-ui-panels

Theming (recommended): install the shared design tokens once so panels — and every other ng-hub-ui library — reads the same palette and dark mode:

npm install ng-hub-ui-ds
@import 'ng-hub-ui-ds/styles/tokens/hub-tokens.css';

It is an optional peer dependency: panels ships sensible fallbacks and works without it, but the tokens give consistent, themeable colours across the whole family (and power the alert variants).

2. Import

The components are standalone — import them directly where you use them:

import {
	PanelsComponent,
	PanelComponent,
	PanelHeadingDirective,
	PanelHeaderDirective,
	PanelFooterDirective
} from 'ng-hub-ui-panels';

3. Use

<hub-panels>
	<hub-panel heading="Overview">First panel content</hub-panel>
	<hub-panel heading="Details">Second panel content</hub-panel>
	<hub-panel heading="Settings">Third panel content</hub-panel>
</hub-panels>

📦 Description

ng-hub-ui-panels unifies the most common content-switching patterns — tabs, pills and accordion — plus a chromeless card layout, behind one declarative component. Drop <hub-panel> panes inside <hub-panels> and pick a type; everything else (keyboard navigation, ARIA wiring, animated collapse, routed panels and form binding) works the same across views. A <hub-panel> can also be used standalone, outside any container, where it renders as a card on its own.

🎯 Features

  • Four visualizationstabs, pills, accordion and card, switched with a single type input.
  • Card layout & standalonetype="card" renders every panel as an always-visible card; a single <hub-panel> also works on its own, outside any container.
  • Content header/footer slotshubPanelHeader and hubPanelFooter mark header/footer bands that render in every view (distinct from the hubPanelHeading nav label).
  • Semantic alertsappearance="alert" with a variant turns a panel into a themed callout (role="alert") driven by the design-system semantic tokens, no per-colour CSS.
  • Strip accent<hub-panels variant> recolours the navigation strip (active/hover tab, active pill, active accordion header) from a single semantic accent; built-in variants use the exact design-system tints and any custom accent is picked up automatically.
  • Forms — implements ControlValueAccessor; bind the active panel(s) to a FormControl or ngModel (single or multiple), with bindValue and compareWith.
  • Routing — a panel with a routerLink turns the content area into a <router-outlet> that follows the URL.
  • Keyboard & a11y — roving tabindex, Arrow/Home/End/Delete keys, and correct role="tablist"/tab/tabpanel and accordion aria-expanded/aria-controls semantics.
  • Strip layoutvertical, justified and scrollable header strips.
  • Accordion optionsmultiple expansion and edge-to-edge flush layout, with an animated grid-based collapse.
  • Custom headers — project any markup with the hubPanelHeading directive.
  • Removable panels — opt-in removable panels close with a ✕ button or the Delete key.
  • Theming — every token is a --hub-panels-* CSS custom property; the accordion view also honours the --hub-accordion-* contract.

📦 Installation

npm install ng-hub-ui-panels

Peer Dependencies

{
	"@angular/common": ">=21.0.0",
	"@angular/core": ">=21.0.0",
	"@angular/forms": ">=21.0.0",
	"@angular/router": ">=21.0.0"
}

⚙️ Usage

Tabs (default)

<hub-panels>
	<hub-panel heading="One">First</hub-panel>
	<hub-panel heading="Two">Second</hub-panel>
</hub-panels>

Pills

<hub-panels type="pills"> … </hub-panels>

Accordion

<hub-panels type="accordion" multiple flush>
	<hub-panel heading="Shipping">…</hub-panel>
	<hub-panel heading="Returns">…</hub-panel>
</hub-panels>

Cards

type="card" drops the navigation strip entirely: every panel is always visible and rendered as a card. Use the hubPanelHeader / hubPanelFooter slots for the card's header and footer bands.

<hub-panels type="card">
	<hub-panel>
		<div hubPanelHeader>Project summary</div>
		Every panel is always visible and styled as a card.
		<div hubPanelFooter>Updated 2 hours ago</div>
	</hub-panel>
	<hub-panel>
		<div hubPanelHeader>Team</div>
		The same header/footer slots work in tabs, pills and accordion too.
	</hub-panel>
</hub-panels>

A single <hub-panel> can be used on its own, with no container — it renders as a card by itself:

<hub-panel>
	<div hubPanelHeader>Standalone card</div>
	Dropped on its own, a hub-panel renders as a card.
	<div hubPanelFooter>
		<button class="btn btn-sm btn-primary">Action</button>
	</div>
</hub-panel>

hubPanelHeader / hubPanelFooter are content bands inside the panel body and render in every view. They are different from hubPanelHeading, which is the navigational tab label / accordion disclosure button.

Alerts

A standalone <hub-panel> becomes a semantic alert with appearance="alert" and a variant. Each variant maps to the design-system --hub-sys-color-<variant>-* token family — there is no per-colour token set — so the alert inherits every theme and dark mode automatically.

<hub-panel appearance="alert" variant="success">Your changes were saved.</hub-panel>
<hub-panel appearance="alert" variant="danger">Something went wrong.</hub-panel>
<hub-panel appearance="alert" variant="warning">Your trial ends in 3 days.</hub-panel>
<hub-panel appearance="alert" variant="info">A new version is available.</hub-panel>

<!-- Omit the variant for a neutral alert -->
<hub-panel appearance="alert">A neutral notice.</hub-panel>

<!-- Alerts support the same header/footer slots as cards -->
<hub-panel appearance="alert" variant="danger">
	<div hubPanelHeader>Payment failed</div>
	Update your billing details to keep your subscription active.
	<div hubPanelFooter><button class="btn btn-sm btn-danger">Update billing</button></div>
</hub-panel>

variant accepts the built-in primary | success | danger | warning | info (rendered with the exact design-system tints) or any custom string: the alert reads --hub-sys-color-<variant> from your app and derives its look with color-mix, so your own accent palette works with no changes here.

<!-- with `:root { --hub-sys-color-brand: #9333ea; }` defined in your app -->
<hub-panel appearance="alert" variant="brand">On-brand callout</hub-panel>

The alert appearance is ignored in the tabs / pills / accordion strip views.

Strip accent (variant)

Give <hub-panels> a variant to set the semantic accent of the navigation strip — the active/hover tab, the active pill and the active accordion header all follow it. It re-bases a single --hub-panels-accent (with derived -emphasis / -subtle roles), so changing one accent recolours the whole strip.

<hub-panels variant="success"> … </hub-panels>
<hub-panels type="pills" variant="danger"> … </hub-panels>
<hub-panels type="accordion" variant="info"> … </hub-panels>

variant accepts the built-in primary | success | danger | warning | info (rendered with the exact design-system tints) or any custom string: the strip reads --hub-sys-color-<variant> from your app and derives the hover/active roles with color-mix, so your own accent palette works with no changes here. Defaults to primary when omitted. Same open-set pattern as the <hub-panel appearance="alert"> accent.

Vertical / Justified / Scrollable

<hub-panels vertical> … </hub-panels>
<hub-panels justified> … </hub-panels>
<div style="max-width: 360px">
	<hub-panels scrollable> … many panels … </hub-panels>
</div>

Reactive forms

<hub-panels [formControl]="selected">
	<hub-panel heading="Light" value="light">…</hub-panel>
	<hub-panel heading="Dark" value="dark">…</hub-panel>
</hub-panels>
selected = new FormControl<string>('dark');

With multiple, the form value is an array. Use bindValue="meta.key" to map each panel's value object to a primitive, and compareWith for custom equality.

Multiple selection

Add multiple to let several panels be open at once. In the tabs / pills views the open panes render side by side (or stacked, when vertical), each at least --hub-panels-pane-min-width wide; the content area scrolls when they overflow. In the accordion view every selected panel expands.

<hub-panels multiple [formControl]="open">
	<hub-panel heading="Summary" value="summary">…</hub-panel>
	<hub-panel heading="Stats" value="stats">…</hub-panel>
	<hub-panel heading="Activity" value="activity">…</hub-panel>
</hub-panels>
open = new FormControl<string[]>(['summary', 'stats']);

Routed panels

<hub-panels>
	<hub-panel heading="Profile" routerLink="/account/profile">Loaded via router-outlet</hub-panel>
	<hub-panel heading="Billing" routerLink="/account/billing">Loaded via router-outlet</hub-panel>
</hub-panels>

When the active panel is routed, the content area renders a <router-outlet> and the active panel follows the current URL (tabs / pills views only).

Custom headers

<hub-panel>
	<ng-template hubPanelHeading>
		<i class="fa-solid fa-gear"></i> Settings <span class="badge text-bg-primary">3</span>
	</ng-template>
	Panel content
</hub-panel>

🪄 API Reference

<hub-panels> inputs

| Input | Type | Default | Description | | --- | --- | --- | --- | | type | 'tabs' \| 'pills' \| 'accordion' \| 'card' | 'tabs' | Visualization of the container. card removes the strip and shows every panel as a card. | | vertical | boolean | false | Stacks the strip beside the content (tabs / pills). | | justified | boolean | false | Stretches headers to equal width. | | scrollable | boolean | false | Adds scroll buttons when the strip overflows. | | isKeysAllowed | boolean | true | Enables keyboard navigation. | | multiple | boolean | false | Accordion: allow several panels expanded at once. | | flush | boolean | false | Accordion: edge-to-edge layout without outer chrome. | | bindValue | string | undefined | Dot-notation path applied to each panel value. | | compareWith | (a, b) => boolean | === | Equality used to match form values. |

<hub-panels> outputs

| Output | Payload | Description | | --- | --- | --- | | panelChange | PanelChangeEvent | Emitted when a different panel is opened ({ current, prev }). |

<hub-panel> inputs

| Input | Type | Default | Description | | --- | --- | --- | --- | | heading | string | undefined | Plain-text header (ignored when a hubPanelHeading template is present). | | id | string | auto | ARIA pairing id. | | value | unknown | id | Value contributed to the form control. | | active | boolean (model) | false | Two-way active/expanded state. | | disabled | boolean | false | Prevents activation. | | removable | boolean | false | Shows a ✕ and enables the Delete key. | | routerLink | string \| string[] | undefined | Turns the panel into a routed panel. | | queryParams | Params | undefined | Query params for routerLink. | | pathMatch | 'route' \| 'full' | 'route' | URL comparison for routed panels. | | customClass | string | undefined | Extra classes on the nav item and pane. |

<hub-panel> outputs

| Output | Payload | Description | | --- | --- | --- | | selectPanel | PanelComponent | Emitted when the panel becomes active. | | deselectPanel | PanelComponent | Emitted when the panel stops being active. | | removed | PanelComponent | Emitted on removal (✕ or Delete). |

Directives

  • hubPanelHeading — marks an <ng-template> inside a hub-panel as its custom navigational header (tab/pill link or accordion disclosure button).
  • hubPanelHeader — marks an element inside a hub-panel as the content header band, rendered at the top of the panel body in every view.
  • hubPanelFooter — marks an element inside a hub-panel as the content footer band, rendered at the bottom of the panel body in every view.

Configuration

Provide PanelsConfig to change defaults application-wide:

providers: [{ provide: PanelsConfig, useValue: { ...new PanelsConfig(), type: 'pills' } }];

🎨 Styling

Everything is themed through --hub-panels-* CSS custom properties. See docs/css-variables-reference.md for the full list.

hub-panels {
	--hub-panels-tab-color-active: #198754;
	--hub-panels-pill-bg-active: #198754;
}

The card view and the header/footer bands have their own tokens (--hub-panels-card-*, --hub-panels-card-gap, --hub-panels-panel-header-*). Because a standalone <hub-panel> has no .hub-panels ancestor, target the panel itself when theming standalone cards:

hub-panel {
	--hub-panels-card-border-radius: 0.75rem;
	--hub-panels-panel-header-bg: #eef2ff;
}

The accordion view also reads the --hub-accordion-* contract, so themes written for ng-hub-ui-accordion keep working.


♿ Accessibility

  • tabs / pills: role="tablist", role="tab", role="tabpanel", roving tabindex and aria-selected.
  • accordion: a disclosure button per panel with aria-expanded / aria-controls and an inert collapsed region.
  • Keyboard: Arrow keys, Home, End move focus; Delete removes a removable panel; Enter/Space toggle accordion headers.

📚 Migration from ng-hub-ui-accordion

ng-hub-ui-panels replaces ng-hub-ui-accordion. Map the markup as follows:

| Accordion | Panels | | --- | --- | | <hub-accordion [multiple]="true"> | <hub-panels type="accordion" multiple> | | <hub-accordion [options]="{ flush: true }"> | <hub-panels type="accordion" flush> | | <hub-accordion-panel title="…"> | <hub-panel heading="…"> | | <ng-template hubAccordionPanelHeader> | <ng-template hubPanelHeading> | | (collapsedChange) | (panelChange) |

Form binding (formControl / ngModel, value, bindValue, compareWith) works the same. Existing --hub-accordion-* theme overrides keep applying.


📊 Changelog

See CHANGELOG.md.


📄 License

MIT © Carlos Morcillo