ng-mandatory-label-span
v1.0.0
Published
Zero-dependency Angular CLI tool and library to automatically inject reactive form mandatory asterisk spans into labels across Angular 8 to 19+ component templates.
Maintainers
Readme
ng-mandatory-label-span 🏷️✨
Zero-dependency Angular developer tool and CLI library to automatically inject reactive form mandatory asterisk spans into
<label>elements across Angular component templates (Angular 8 to 19+).
🎯 The Problem
In enterprise Angular applications, form inputs with dynamic validation requirements must display a mandatory indicator (usually an asterisk *) inside their <label>.
Manually finding and editing <label> tags across hundreds of .component.html files to bind them to dynamic portal/form configuration variables (e.g. *ngIf="portal?.firstName?.isMandatory") is tedious, repetitive, and error-prone.
ng-mandatory-label-span automates this with an intelligent template codemod:
- 🔍 Scans all
.component.htmlfiles across your Angular project. - 🏷️ Pairs form controls (
formControlName) with their corresponding<label>:- Preceding labels (
<label>First Name</label><input formControlName="firstName">) - Explicit labels via
forattributes (<label for="fname">matching<input id="fname">) - Wrapping labels (
<label>Agree <input formControlName="agree"></label>)
- Preceding labels (
- 🧠 Infers the portal/model variable dynamically (e.g.
portal?.fieldName?.isMandatory,candidatePortal, etc.). - 🛡️ Prevents duplicates: Safely detects existing mandatory spans, asterisks, or conditions and skips them.
- ⚡ Zero dependencies: Pure Node.js, lightning fast, works in any CI/CD or developer terminal.
- 🔒 Safe by default: Runs in dry-run preview mode until you pass
--write.
🚀 Quick Start (Zero Install)
Run directly in any Angular workspace with npx:
# Preview changes (safe dry-run, no files modified):
npx ng-mandatory-label-span
# Apply and write changes directly to your component templates:
npx ng-mandatory-label-span --write(You can also use the shorthand aliases):
npx add-mandatory-label-span --write
# or
npx ng-label-spans --write📦 Installation
Add it to your Angular project as a development dependency:
npm install --save-dev ng-mandatory-label-spanOr using Yarn / pnpm:
yarn add -D ng-mandatory-label-span
# or
pnpm add -D ng-mandatory-label-spanAdd convenience scripts to your package.json:
{
"scripts": {
"add-labels": "ng-mandatory-label-span --write",
"check-labels": "ng-mandatory-label-span"
}
}Now run anytime with:
npm run add-labels🛠️ CLI Options & Usage
npx ng-mandatory-label-span [options]| Flag | Shorthand | Description | Default |
| :--- | :--- | :--- | :--- |
| --write | -w | Apply and write updates directly to .component.html files | false (dry-run) |
| --dry-run | -d | Explicitly enforce preview mode | true |
| --root <path> | -r <path> | Directory to scan for Angular templates | Current working directory |
| --class <name> | | CSS class applied to the mandatory <span> | "hays-imp-field" |
| --symbol <char> | | Character / symbol placed inside the span | "*" |
| --portal <var> | | Default/fallback portal variable name | Inferred from template |
| --control-flow | | Generate modern Angular 17+ @if syntax | false (*ngIf) |
| --legacy-skip-spans| | Skip label if it already contains any <span> tag | false |
| --help | -h | Display the help manual | |
| --version | -v | Display package version | |
Practical Examples
1. Scan a specific submodule
npx ng-mandatory-label-span --root=./src/app/modules/candidate --write2. Custom CSS class and symbol
npx ng-mandatory-label-span --class="text-danger mandatory-star" --symbol="*" --write3. Modern Angular 17+ Control Flow (@if)
npx ng-mandatory-label-span --control-flow --write4. Explicit Portal Variable Override
npx ng-mandatory-label-span --portal="candidatePortal" --write💡 Transformation Example
Before:
<div class="form-group" *ngIf="portal?.firstName?.isEditable">
<label>First Name</label>
<input type="text" formControlName="firstName" class="form-control" />
</div>
<div class="form-group" *ngIf="portal?.email?.isDisplay">
<label for="emailInput">Email Address</label>
<input id="emailInput" type="email" formControlName="email" class="form-control" />
</div>After running npx ng-mandatory-label-span --write:
<div class="form-group" *ngIf="portal?.firstName?.isEditable">
<label>First Name <span *ngIf="portal?.firstName?.isMandatory" class="hays-imp-field">*</span></label>
<input type="text" formControlName="firstName" class="form-control" />
</div>
<div class="form-group" *ngIf="portal?.email?.isDisplay">
<label for="emailInput">Email Address <span *ngIf="portal?.email?.isMandatory" class="hays-imp-field">*</span></label>
<input id="emailInput" type="email" formControlName="email" class="form-control" />
</div>💻 Programmatic Usage
You can also import and use the transformer programmatically in your build scripts, schematics, or CI/CD pipelines:
CommonJS / Node:
const { transformHtml, walkHtmlFiles, run } = require('ng-mandatory-label-span');
// Transform an in-memory template string:
const html = `
<div *ngIf="portal?.mobile?.isEditable">
<label>Mobile Number</label>
<input formControlName="mobile" />
</div>
`;
const result = transformHtml(html, {
className: 'mandatory-star',
symbol: '*'
});
console.log(result.updated);
console.log(`Injected ${result.addedCount} mandatory spans`);TypeScript:
import { transformHtml, TransformResult } from 'ng-mandatory-label-span';
const result: TransformResult = transformHtml(templateContent, {
portalVar: 'userConfig'
});🌐 Angular Compatibility
| Angular Version | Supported | Notes |
| :--- | :---: | :--- |
| Angular 8 - 16 | ✅ | Full compatibility using universal *ngIf and safe navigation ?. |
| Angular 17 - 19+ | ✅ | Compatible with both standard *ngIf and modern @if control flow |
| Zero Dependencies | ✅ | No compiler lock-ins, no @angular/core peer mismatch issues |
📄 License
MIT © 2026 Kuldeep Kaushik
