anchor · design system
Anchor was the design system that came before Meridian. Three internal
packages: a main component package, a shared core runtime, and a
second-generation UI library. Roughly 86 Vue 2 components compiled
to native custom elements via vue-custom-element,
lazy-mounted by a document-wide MutationObserver, and styled with a
Sass-driven token system. The codebase where the framework-agnostic
ideas were incubated under real enterprise constraints.
Architectural overview of the component library »
what it was
Three packages, scoped together under a private internal npm registry, consumed by every front-end app inside the enterprise:
- main components
- Roughly 86 Vue components covering forms, charts, modals, navigation, video, and content layouts. Storybook docs. The compilation entrypoints that emit a single browser bundle of custom elements.
- core runtime
- Shared runtime: Sass tokens and breakpoints, an event bus, Vue filters, mixins, plugins, and the custom directives the components built on top of (intersection, viewport bounds, drawer behavior, anchor offsets, target binding).
- second-generation ui
- A second library with broader coverage and a “hero sandbox” playground for end-to-end scenarios that standard Storybook stories couldn’t cover.
the singleton runtime
Every component shared a single runtime, owned by a singleton class installed as a Vue plugin. The pattern: a small set of utility plugins (viewport, key-code aliases, focus management), a shared event bus, a registered set of Vue filters, and a quiet version banner at boot. Same architectural posture I would later port forward to Meridian, different framework era.
lazy hydration via MutationObserver
86 components is too many to ship upfront. The classic answer was code-splitting; the harder problem was deciding which bundles to load on which page when adopters didn’t know what their CMS templates were going to include.
The solution: one MutationObserver watching the whole
document. When any custom element with the system’s tag prefix
appears in the DOM, the matching component chunk is dynamic-imported
and registered on the fly. Pages that include the navbar but not the
chart pay for only the navbar. Pages that conditionally render the
chart pay for it only if the chart is actually rendered. Decoupled
from the host framework’s scheduler.
the directives
Some of the most-reused primitives in Anchor weren’t components, they were custom Vue directives. Two notable examples:
v-intersect wraps a single shared
IntersectionObserver with a WeakMap for
per-element callbacks. Lazy-load images, animation triggers,
infinite-scroll feeds, all built on this one primitive.
v-bounds toggles class names based on
which viewport edges the element is currently touching. Used by
sticky-state components, sidebar positioning, in-page navigation
indicators. Cheaper and more declarative than per-component scroll
listeners.
enterprise constraints that shaped the design
- Private internal npm registry, no public dependencies allowed. Every dependency had to be vetted through internal security. That pushed the team toward small, standalone primitives instead of a kitchen-sink framework. Today’s “just install Lit” wasn’t an option; Anchor had to ship its own component runtime.
- Node 18 + openssl-legacy-provider for Vue 2 builds. The system had to keep shipping on a modern Node version while Vue 2 kept aging. Real evidence of long-running enterprise discipline: patch the build, write the README, keep going.
- Multiple consuming frameworks (Vue, Angular, AEM/Java). The framework-agnostic web-component approach was the only way to serve all three from one source. Meridian scaled this; Anchor proved it worked.
- POM-based artifact lifecycle. The npm packages had to satisfy a Maven parent POM’s versioning and publishing rules. Bonus complexity that taught the team how to treat front-end packages with the same release discipline as a Java backend service.
- Brand color and tokens via Sass. CSS custom properties weren’t broadly safe across all consumer browsers Anchor had to support. Tokens lived in Sass and were inlined at build time. Meridian later moved them to custom properties; Anchor was the constraint study.
what carried forward
The most direct lineage from Anchor to Meridian:
-
The Vue-source-to-Web-Component compilation approach.
Anchor used
vue-custom-elementon Vue 2; Meridian replaced it with Vue 3’s nativedefineCustomElement. Same architectural premise; framework-agnostic distribution from a single source. - The directives: intersection, bounds, drawer, anchor offsets, survived almost verbatim into the Meridian composables layer.
- The monorepo / multiple packages shape. Anchor used Yarn workspaces; Meridian uses Nx, but the partitioning logic is the same: a core runtime, a component library, framework-specific adapters.
- The Storybook-first documentation model with adopter playgrounds that go beyond standard story isolation.
- The token system shape, spacing, typography, color, breakpoints, structured the same way, just promoted from Sass to CSS custom properties when the browser support landed.
stack
- Frontend
- Vue 2.7, custom elements via
vue-custom-element - Build
- Vue CLI, Webpack, Babel, PostCSS, Sass
- Distribution
- Private internal npm registry, three published packages
- Documentation
- Storybook + custom hero-sandbox playground
- Testing
- Jest unit tests + TestCafe visual-regression baseline
- Monorepo
- Yarn workspaces across the internal scope
More: component-library overview »
Related: Meridian
(the successor) · Skeletor
(the agency-era precursor) ·
Building the design system