Hook — 05 : 55 a.m., Cartagena ↔ São Paulo sprint demo
Waves slapped the old city walls while I screenshared a prototype “Button → Card” design system with Lúcio, a junior dev dialing in from Brazil. We’d shipped four Angular apps that month—each with its own slightly different primary-button component. Marketing’s red turned to maroon in the checkout flow, and QA complained of mis-aligned tooltips on low-dpi tablets. “Enough copy-paste,” I said, sipping tinto. We opened the Angular CLI, generated a workspace library, published it to our private Verdaccio registry, and within an hour every product shared one source of visual truth. – That cross-continent refactor is today’s roadmap: you’ll learn how to architect, package, version, and consume a reusable UI library in Angular 18, without losing design fidelity—or your teammates’ sanity across time zones.


Why Roll Your Own Library?

Pain PointWhat HurtsAngular Library Fix
Diverging button styles across appsBrand inconsistency, higher QA timeSingle source of CSS + TS truth
Copy-pasted componentsBloated bundles, tangled bug fixesShip once, consume everywhere
Multiple teams, multiple reposMerge conflicts & code driftWorkspace libraries live beside apps, versioned together
Design token changesManual edits in every projectLibrary exposes SCSS or CSS Vars; update package, bump version

A solid library means faster sprints, lower bundle sizes, and a UI that feels coherent from Mexico City fintech dashboards to Costa Rican surf-school booking sites.


Anatomy of an Angular Library


Step-by-Step Walkthrough

1 — Create a Workspace and Library

bashCopyEdit# ① scaffold workspace without an initial app
ng new latin-ui --create-application=false --style=scss
cd latin-ui

# ② generate a library
ng g library ui --prefix=lu --style=scss

Folder tree:

cssCopyEditprojects/ui/
  src/
    lib/
      button/
        button.component.ts
        button.component.html
        button.component.scss
    public-api.ts
  ng-package.json

2 — Build the First Component

tsCopyEdit// button.component.ts
import { Component, Input } from '@angular/core';

@Component({
  selector: 'lu-button',
  template: `<button
      [class]="variant"
      [disabled]="disabled"
      type="button">
      <ng-content></ng-content>
    </button>`,
  styleUrls: ['./button.component.scss'],
})
export class ButtonComponent {
  @Input() variant: 'primary' | 'secondary' | 'danger' = 'primary';
  @Input() disabled = false;
}
scssCopyEdit/* button.component.scss */
$primary: #005dff;
$secondary: #64748b;
$danger: #ef4444;

button {
  padding: .5rem 1rem;
  border-radius: .5rem;
  font-weight: 600;
  &.primary { background: $primary; color: #fff; }
  &.secondary { background: $secondary; color: #fff; }
  &.danger { background: $danger; color: #fff; }
  &:disabled { opacity: .5; cursor: not-allowed; }
}

Export via public-api.ts:

tsCopyEditexport * from './src/lib/button/button.component';

3 — Build & Link Locally

bashCopyEditng build ui
# link for local dev
npm link dist/ui

In any local Angular app:

bashCopyEditnpm link @latin/ui

Import module (Angular 18 standalone):

tsCopyEditbootstrapApplication(AppComponent, {
  providers: [importProvidersFrom(UiModule)]
});

4 — Add a Theming Hook with SCSS or CSS Variables

Expose design tokens:

scssCopyEdit// projects/ui/src/styles/_tokens.scss
:root {
  --lu-primary: #005dff;
  --lu-secondary: #64748b;
  --lu-danger: #ef4444;
}

In component styles use var(--lu-primary); apps override via global stylesheet—no rebuild of library needed.


Publishing & Versioning Strategy

StageCommandNotes
Build for prodng build ui --configuration=productionProduces Ivy & View Engine bundles
Bump versionnpm version minorFollow semver; changelog via commitlint
Publishnpm publish dist/ui --access public or --registry http://your-verdaccioScope under @latin
Consumenpm i @latin/ui@^1.3.0Apps pick up compatible majors

Tip — Use Nx or Bazel for incremental builds in huge mono-repos; Angular 18 builder caching already speeds cold builds ~60 %.


Common Pitfalls & Fixes

PitfallSymptomRemedy
Forgot to add component to exports:App template error: “’lu-button’ is not a known element”Add to @NgModule({ exports: […] }) or export in public-api.ts
Mixing View Engine & IvyBuild fails with NG6002Always build libraries with Angular 18+; remove enableIvy:false
Shadow DOM leakStyles override host appUse ::ng-deep only for purposeful overrides; prefer encapsulated SCSS
Breaking changes in minorApps crash after npm updateFollow semver strictly; bump major for API breaks

Remote-Work Insight ☕

While freelancing from Panama City, we had satellite internet with 500 ms latency. Publishing to public npm took forever. We mirrored a Verdaccio registry on a local Raspberry Pi in the coworking. npm publish and npm install became LAN-fast; weekly design tweaks rolled out to three micro-frontends before the afternoon storm cut power.


Performance & Accessibility Checkpoints

  1. Bundle Sizenpm pack dist/ui produces <20 KB min+gz by tree-shaking unused components.
  2. Lighthouse — Ensure colored buttons pass contrast ≥ 4.5:1; document token overrides for dark mode.
  3. Rendering — Angular 18 OnPush change detection by default in library components; avoid two-way binding inside.
  4. Keyboard & ARIA — Expose [attr.aria-label] pass-throughs; publish Storybook docs with keyboard scenarios.

Call-Out Table — Key CLI Commands

CLIPurpose
ng g library ui --style=scss --prefix=luGenerate library
ng build uiBundle Ivy-ready package
ng test uiRun Jest/Karma tests for lib
ng add @storybook/angularDocs + visually test components
npm publish dist/uiDistribute package

SVG Diagram Idea

Lane 1 — Developer: ng g library ui ➜ code components.
Lane 2 — Builder: ng build uing-packagr bundles (fesm2020, d.ts).
Lane 3 — Registry: publish package.
Lane 4 — Consumer App: npm install @latin/ui ➜ imports & treeshakes.


Wrap-Up

A reusable UI library is a passport between projects and teams: design changes propagate in minutes, not sprints; bug fixes land once, not everywhere. Angular 18’s library tooling, Ivy build graph, and standalone components make the process almost vacation-easy—perfect for devs juggling hot-fixes from Dominican rooftops to Colombian coffee farms. Start small (buttons), automate versioning, enforce tokens, and watch your front-end velocity soar.

Questions or stories from your own library adventures? Drop a comment—I’ll answer between layovers and late-night arepa sessions.

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x