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

angular-dockable-desktop

v1.9.0

Published

A dockable layout engine and window manager for Angular: split docking, tab groups, floating windows, and zero-unmount panels that keep their live state across every layout change.

Readme

angular-dockable-desktop

A window manager and dockable layout engine for Angular 22. Fluid grid splits, tabbed groups, floating resizable windows, a taskbar with live previews, zero-unmount state preservation, sidebars and toolbars, side panels and modals, toasts, context menus, per-panel overlays, internationalisation and RTL.

Live demo  |  Users manual  |  Design decisions  |  Parity with the React and Vue versions  |  Changelog

Written as a native Angular library — standalone components, signals, input() / model() / output(), inject(), typed templates, zoneless-first — not as a transliteration of its siblings react-dockable-desktop and vue-dockable-desktop. It reads and writes the same serialised layout format as both, byte for byte, so a layout saved by any of the three loads in the others.

Versioning. ndd follows its own semver. This release tracks vue-dockable-desktop 1.1.1 and, through it, react-dockable-desktop 6.3.1, feature by feature in docs/PARITY.md — plus react-dockable-desktop 7.2.0 and 7.3.0's skin branding.

Install

npm install angular-dockable-desktop

Requires Angular 22 (@angular/core and @angular/common as peers), and a browser with CSS color-mix() (Chrome / Edge 111, Safari 16.2, Firefox 113 or later). No runtime dependencies beyond tslib, which the Angular packager declares for every library and every Angular app already has — no CDK, no UI kit. Works zoneless (the default for a new Angular app) and with zone.js, and server-renders and hydrates.

Quick start

Add the stylesheet to angular.json (projects.<app>.architect.build.options.styles), first:

"styles": ["angular-dockable-desktop/styles.css", "src/styles.css"]

A panel is any standalone component:

// src/app/hello-panel.ts
import { Component } from '@angular/core';
import { injectPanel } from 'angular-dockable-desktop';

@Component({
  selector: 'app-hello-panel',
  template: `<p class="hello">Hello from a panel ({{ panel.id }})</p>`,
})
export class HelloPanel {
  protected readonly panel = injectPanel();
}

Register it where the application is configured:

// src/app/app.config.ts — add to `providers`
provideDockableDesktop({ panels: { hello: { component: HelloPanel, defaultOptions: { title: 'Hello' } } } }),

And render the desktop:

// src/app/app.ts
import { Component, inject } from '@angular/core';
import { NddDesktop, Workspace } from 'angular-dockable-desktop';

@Component({
  selector: 'app-root',
  imports: [NddDesktop],
  template: `<ndd-desktop class="ndd-fill-viewport" />`,
})
export class App {
  constructor() {
    inject(Workspace).openPanel('hello-1', 'hello');
  }
}

That exact code is what the release gate installs into a fresh ng new --ssr --zoneless application, builds, prerenders, serves and hydrates.

Workspace is an ordinary injectable, so every action is a method on it, from any component or service — and its state is signals:

import { computed, inject } from '@angular/core';
import { Workspace } from 'angular-dockable-desktop';

// In any component, directive or service:
const ws = inject(Workspace);
// openPanel(instanceId, panelKey, options?) — the id is yours, the key is from `panels`.
ws.openPanel('overview', 'hello', { title: 'Overview' });
ws.floatPanel('overview', { x: 80, y: 60, width: 480, height: 320 });
localStorage.setItem('layout', ws.saveLayout());
const open = computed(() => Object.keys(ws.panels()).length);

Mount <ndd-context-menu />, <ndd-modals />, <ndd-side-panels /> and <ndd-toasts /> once, anywhere, for menus, the unsaved-changes question, drawers and notifications (chapter 1).

Features

  • Split-docking grid — drag a tab to any edge of a group to split it, to its centre to join it, or to a workspace edge for a full-width row; mouse, pen and touch

  • Floating windows — eight-direction resize, maximise, minimise, and corner anchoring that survives resizes and RTL

  • Zero unmount — a panel is created once and moved, never re-created, across docking, floating, tab switches and the taskbar; maps keep their WebGL context, editors their undo history, and scroll and focus are restored explicitly

  • Taskbar with live previews — the thumbnail is the panel's own DOM, not a screenshot

  • Panel lifecycle — injectPanel() signals for active, minimised, floating, size and dirty; close guards; trackDirty() for Signal Forms; an unsaved-changes question on close

  • Sidebar and toolbar — primary and secondary sidebars and a workspace toolbar, bound with [( )], with per-panel contributions that follow the active panel

  • Panel overlay — toolbars on a panel's own edges and floating widgets inside it, opened declaratively or from data

  • Overlays — a modal stack with NddModalRef.afterClosed(), side drawers, a confirm dialog, toasts callable from anywhere, and context menus with a typed custom template

  • Layout serialisation — the whole workspace as one JSON string, byte-compatible with rdd and vdd, including each panel's own saved state

  • Theming — seven skins plus your own, light and dark, each with its own font, 126 documented --ndd-* tokens; the library styles only its own DOM and coexists with Bootstrap, Tailwind and Angular Material

  • Branding — your company's colour and font on any built-in skin, from three variables:

    :root {
      --ndd-brand-accent: #e4002b;                 /* every accent use, in every skin, dark and light */
      --ndd-brand-on-accent: #ffffff;              /* text on a brand-coloured fill — a dark one for light brands */
      --ndd-font-family: 'Acme Sans', sans-serif;  /* your font (the library loads none) */
    }

    Point them at your UI framework's theme to follow it — var(--mat-sys-primary) (Angular Material 3), var(--bs-primary) (Bootstrap). Your own surfaces and corner shape, too:

    :root:not([data-color-scheme="light"]) {  /* dark: the attribute's absence */
      --ndd-brand-surface: #0b1f3a;   /* app background — panels, bars and borders derive from it */
      --ndd-brand-text: #e8eef7;      /* main text — set both, or neither */
    }
    :root { --ndd-radius-scale: 0; }  /* 0 square · 1 each skin's own · 1.5 rounder */

    See Brand your app

  • i18n and RTL — every string goes through one formatMessage function; a signal-backed locale relabels live; setDirection('rtl') mirrors the whole workspace structurally

  • Accessible — WAI-ARIA tabs, menus and dialogs, verified with axe-core; no change detection on idle pointer movement

  • Typed — strict templates, typed template contexts, typed events

Documentation

| | | |---|---| | Live demo | Every capability in one application, published from projects/demo by GitHub Pages on each push to main | | docs/manual/ | The users manual — 13 chapters, starting with Getting started | | docs/manual/12-migrating.md | Coming from react-dockable-desktop or vue-dockable-desktop | | docs/decisions/ | Architecture decision records | | docs/PARITY.md | The API map to vdd, the test map, and every deliberate divergence (D1–D16, N1–N17) | | docs/PROGRESS.md and docs/evidence/ | One row and one written record per milestone gate | | CHANGELOG.md | What changed |

License

MIT