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

@paulelyson/elyui

v0.9.1

Published

Developer-friendly Angular UI components. Minimalist, themeable with plain CSS variables.

Readme

elyui

Developer-friendly UI components for Angular.

→ Live demo — every component, every variant, every size, on one page.


Imagine building an autocomplete with a form control

In Angular:

imports: [
  ReactiveFormsModule,
  MatFormFieldModule,
  MatInputModule,
  MatAutocompleteModule,
  AsyncPipe,
]
export class Example implements OnInit {
  equipment = new FormControl<Option | string>('');
  options: Option[] = [
    { value: 'monitor', label: 'Monitor' },
    { value: 'keyboard', label: 'Keyboard' },
    { value: 'dock', label: 'Docking station' },
  ];
  filtered!: Observable<Option[]>;

  ngOnInit(): void {
    this.filtered = this.equipment.valueChanges.pipe(
      startWith(''),
      map((value) => (typeof value === 'string' ? value : (value?.label ?? ''))),
      map((label) =>
        this.options.filter((option) =>
          option.label.toLowerCase().includes(label.toLowerCase()),
        ),
      ),
    );
  }

  displayFn(option: Option): string {
    return option?.label ?? '';
  }
}
<mat-form-field>
  <mat-label>Equipment</mat-label>
  <input matInput [formControl]="equipment" [matAutocomplete]="auto" />
  <mat-autocomplete #auto="matAutocomplete" [displayWith]="displayFn" autoActiveFirstOption>
    @for (option of filtered | async; track option.value) {
      <mat-option [value]="option">{{ option.label }}</mat-option>
    }
  </mat-autocomplete>
</mat-form-field>

In elyui:

imports: [ReactiveFormsModule, Autocomplete]
export class Example {
  equipment = new FormControl('');
  options = ['Monitor', 'Keyboard', 'Docking station'];
}
<ely-autocomplete label="Equipment" [options]="options" [formControl]="equipment" />

Same filtering, same keyboard navigation, same ARIA roles. No filter pipe, no displayWith, no wrapper element. options takes a plain string[] or { value, label } objects, and the control holds the selected value.


Or three buttons with icons and appearances

In Angular:

<button matButton="filled">
  <mat-icon>save</mat-icon>
  Save
</button>

<button matButton="outlined" class="btn-danger btn-sm">
  <mat-icon>delete</mat-icon>
  Delete
</button>

<button matIconButton class="btn-accent">
  <mat-icon>bookmark</mat-icon>
</button>

Material has no size scale and no danger or accent semantic, so those two are your CSS to write — per state, forever:

.btn-danger {
  --mdc-outlined-button-label-text-color: #b91c1c;
  --mdc-outlined-button-outline-color: #b91c1c;
}
.btn-danger:hover { background: #fef2f2; }

.btn-sm {
  --mdc-outlined-button-container-height: 32px;
  font-size: 13px;
  padding: 0 10px;
}

.btn-accent { --mdc-icon-button-icon-color: #7c3aed; }

In elyui:

<ely-button appearance="filled" variant="primary" icon="save">Save</ely-button>
<ely-button appearance="outlined" variant="danger" size="xs" icon="delete">Delete</ely-button>
<ely-button appearance="icon" variant="accent" icon="bookmark" />

No stylesheet. appearance is filled · tonal · outlined · ghost · link · icon, variant is neutral · primary · accent · success · warning · danger, size is xs · sm · md · lg.


Install

npm install @paulelyson/elyui @angular/material @angular/cdk

@angular/core, @angular/common, @angular/forms, and rxjs are also peer dependencies, but you already have those in any Angular app.

Requires Angular 21+.

Setup

1. Import the theme. Add it to your angular.json styles array (or @import it from your own global stylesheet). This defines every CSS variable the components render with — without it, components render unstyled:

"styles": [
  "node_modules/@paulelyson/elyui/styles/elyui.css",
  "src/styles.css"
]

2. Load the Material Icons font. Icon — and anything that renders one internally, which is most things — uses ligature icon names and expects this font in your index.html:

<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />

That's it — there's no third step. You do not need provideAnimationsAsync() or the @angular/animations package.

Usage

Components are standalone — import the ones you use, no NgModule:

import { Component } from '@angular/core';
import { Button, Badge, Icon } from '@paulelyson/elyui';

@Component({
  selector: 'app-example',
  imports: [Button, Badge, Icon],
  template: `
    <ely-button appearance="filled" variant="primary" icon="save">Save</ely-button>
    <ely-badge variant="success">Active</ely-badge>
    <ely-icon name="star" size="lg" variant="warning" tooltip="favorite" />
  `,
})
export class Example {}

Snackbar is opened imperatively through its service — no component to import, no template markup:

import { SnackbarService } from '@paulelyson/elyui';

export class Example {
  constructor(private snackbar: SnackbarService) {}

  save(): void {
    this.snackbar.openSnackbar({ type: 'success', message: ['Saved.'], icon: 'check' });
  }
}

Theming

Every size- and color-dependent value is a CSS variable — no Sass, no theming API, no rebuild. Override any of them after importing elyui.css:

:root {
  --color-bg-primary-idle: #d1fae5;
  --color-text-primary-default: #047857;
  --border-radius-md: 6px;
}

The full token list is short and readable — skim styles/elyui.css.

Components

Icon · Badge · Button · Toggle · Snackbar (+ SnackbarService) · SegmentedControl · TextInput (ely-input) · Textarea · Dropdown · Autocomplete · Datepicker · DateRangePicker · DataRow · FileInput · Tab · Avatar · VerticalStepper · TitleSection · Tooltip · Menu · Navbar

Tooltip is a directive rather than a component, so it goes on any element — elyui's own or plain HTML:

<button elyTooltip="Save this draft">Save</button>
<ely-icon name="info" elyTooltip="Optional field" tooltipPosition="right" tooltipVariant="accent" />

It takes tooltipPosition (above · below · left · right, flipping automatically when the preferred side will not fit), tooltipSize, tooltipVariant, tooltipShowDelay, tooltipHideDelay, tooltipHasArrow, tooltipHasBorder, and tooltipDisabled. An empty string shows nothing, so binding a value that may be blank is safe.

Menu is a dropdown of actions on the CDK menu, so outside-click and Escape to close, focus return, arrow-key navigation and the ARIA roles come built in. Items are data; whatever you project becomes the trigger, and elyMenuHeader elements become a header in the panel:

<ely-menu icon="more_vert" triggerLabel="More actions" [items]="actions" (itemSelected)="onAction($event)" />

<ely-menu [items]="accountActions">
  <ely-avatar label="Kace Cee" [showLabel]="true" />
  <strong elyMenuHeader>Kace Cee</strong>
</ely-menu>

A MenuItem is { value, label, icon?, variant?, disabled?, dividerBefore? }, and (itemSelected) emits the whole item. It also takes position (below-start · below-end · above-start · above-end, flipping when it will not fit), size, disabled, hasBorder and hasFocusGlow, and emits (opened) and (closed). The trigger is already a <button>, so project non-interactive content into it — never another button.

The panel's colours are --color-bg-menu, --color-bg-menu-hover and --color-border-menu (the last also draws the header rule and dividers). The panel renders in an overlay on document.body, outside the ely-menu element, so set them on :root in a global stylesheet — on the host they never reach it.

Navbar is a responsive top bar: a brand link, router links, and an end slot for whatever you project. The current page's link is underlined and gets aria-current="page"; below collapseAt (768px by default) the links fold into an ely-menu hamburger while the end slot stays put:

<ely-navbar brand="Inventory" brandLink="/" [links]="links">
  <ely-button>Log in</ely-button>
</ely-navbar>

A NavLink is { label, route, exact? }. It also takes brandImage (a decorative logo before the brand text — brand stays the link's accessible name), transparent, label (the <nav> landmark's name, default Main), size, variant, hasBorder and hasFocusGlow. Height, inline padding and link spacing are per-app tokens rather than inputs — ely-navbar { --navbar-height: 75px; } — and --color-bg-navbar sets its background. Navbar requires @angular/router (a peer dependency from 0.9.0) and a provideRouter() in your app config.

Most accept size (xs · sm · md · lg), variant (neutral · primary · accent · success · warning · danger), and hasBorder for a seamless borderless look. Nothing is forced on you — don't want the focus glow? [hasFocusGlow]="false". The library has opinions, not rules.

Status

Pre-1.0. The API may still shift as more components land. Pin the version if that bothers you.

License

MIT.