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

@lint-suite/eslint-plugin-no-unstyled-classes

v1.0.0

Published

Disallow Angular template classes that no component stylesheet selects

Readme

@lint-suite/eslint-plugin-no-unstyled-classes

@lint-suite/eslint-plugin-no-unstyled-classes is an ESLint rule for Angular HTML templates. It reports static template class names that no component, linked, or configured global CSS/SCSS stylesheet selects, helping keep Angular and CSS styling contracts aligned.

Requirements

  • ESLint ^10.9.1
  • TypeScript 6.0.3 or newer
  • Angular compiler 22.1.5, installed with this plugin
  • @angular-eslint/template-parser 22 for parsing Angular templates
  • Node.js 24

The package is ESM-only.

Installation

pnpm add -D @lint-suite/eslint-plugin-no-unstyled-classes eslint @angular-eslint/template-parser typescript

Configuration

// eslint.config.mjs
import * as templateParser from '@angular-eslint/template-parser';
import noUnstyledClasses from '@lint-suite/eslint-plugin-no-unstyled-classes';

export default [
  {
    files: ['**/*.html'],
    languageOptions: { parser: templateParser },
    plugins: { 'no-unstyled-classes': noUnstyledClasses },
    rules: {
      'no-unstyled-classes/no-unstyled-classes': 'error'
    }
  }
];

The plugin contains only the no-unstyled-classes rule. The plugin namespace in the configuration is consumer-defined.

Rule behavior

The rule reads static class tokens, [class.name] bindings, and literal class names from [class], interpolated class attributes, routerLinkActive, animate.enter, and animate.leave. It deliberately does not analyze [ngClass].

For an Angular component template, styles come from styleUrl, styleUrls, and inline styles in the adjacent component metadata. If metadata declares none, a sibling .scss or .css file is used. Plain HTML files may link relative stylesheets with <link rel="stylesheet">. Linked paths are resolved relative to the consumer file, not relative to this installed package.

SCSS nesting, selector lists, interpolated selectors, and @use, @import, and @forward partials are resolved. Absolute and root-relative stylesheet links are ignored. A template with no readable stylesheet is not reported.

Options

{
  rules: {
    'no-unstyled-classes/no-unstyled-classes': [
      'error',
      {
        ignoreClassPatterns: ['^(js|qa|mat|cdk|mdc)-', '^u-'],
        globalStyles: ['src/styles.scss']
      }
    ]
  }
}
  • ignoreClassPatterns defaults to ['^(js|qa|mat|cdk|mdc)-']. Each string is compiled with the Unicode regular-expression flag. A configured array replaces the default.
  • globalStyles defaults to []. Paths are resolved from ESLint's working directory and merged into every template's known classes. Missing files are ignored.

Examples

Each fixture is checked by this rule alone. Every filename comment identifies a required companion file. Examples using globalStyles show a non-default option; all others use default options.

Valid examples

1. Static class selected by a sibling stylesheet

<!-- card.component.html -->
<div class="card"></div>
// card.component.scss
.card {}

2. Default framework-prefix exemption

<!-- hooks.component.html -->
<button class="mat-button js-hook"></button>
// hooks.component.scss
.other {}

3. Class selected by a component styleUrl

// card.component.ts
import { Component } from '@angular/core';
@Component({ templateUrl: './card.component.html', styleUrl: './card.component.scss' })
export class CardComponent {}
<!-- card.component.html -->
<div class="card"></div>
// card.component.scss
.card {}

4. Class selected by inline component styles

// banner.component.ts
import { Component } from '@angular/core';
@Component({ templateUrl: './banner.component.html', styles: ['.banner {}'] })
export class BannerComponent {}
<!-- banner.component.html -->
<div class="banner"></div>

5. Class selected by configured global styles

// Non-default rule option
{ globalStyles: ['src/styles.scss'] }
<!-- src/app.component.html -->
<main class="app-shell"></main>
// src/styles.scss
.app-shell {}

6. Template without a readable stylesheet

<!-- plain.component.html -->
<div class="unresolved"></div>

No sibling stylesheet, component metadata, or linked stylesheet is present, so the rule does not report.

Invalid examples

1. Missing static class

<!-- card.component.html -->
<div class="card missing"></div>
// card.component.scss
.card {}

missing is reported.

2. Missing [class.name] binding

<!-- card.component.html -->
<div [class.selected]="active"></div>
// card.component.scss
.card {}

selected is reported.

3. Missing class in an ordinary linked HTML stylesheet

<!-- page.html -->
<link rel="stylesheet" href="./page.css">
<main class="missing"></main>
/* page.css */
.page {}

missing is reported.

4. Missing class despite component styleUrls

// hero.component.ts
import { Component } from '@angular/core';
@Component({ templateUrl: './hero.component.html', styleUrls: ['./hero.component.scss'] })
export class HeroComponent {}
<!-- hero.component.html -->
<section class="hero missing"></section>
// hero.component.scss
.hero {}

missing is reported.

5. Global class without the non-default globalStyles option

<!-- src/app.component.html -->
<main class="app-shell"></main>
// src/app.component.scss
.app-content {}
// src/styles.scss (not configured)
.app-shell {}

With default options, app-shell is reported because the global stylesheet is not part of this template's styles.

Cache

Parsed component metadata, templates, and stylesheets are cached in memory and persisted under node_modules/.cache/lint-suite in the consumer working directory. Cache files are isolated by this package's name, version, and cache format. Set LINT_SUITE_CACHE_DIR to choose another directory or LINT_SUITE_CACHE=0 to disable persistence.

License

MIT