Angular Validator - Setup

Smart UI for Angular supports both standalone components (bootstrapApplication) and NgModule-based apps (bootstrapModule(AppModule)). Steps 1-5 show the standalone path; the section below shows the NgModule path with the same package and styles.

Demo source (Smart UI repo): angular/src/validator/overview

1 NPM Install

Install the smart-webcomponents-angular package:

npm install smart-webcomponents-angular

2 Register styles

Add the default Smart UI stylesheet to angular.json -> projects -> <your-project> -> architect -> build -> options -> styles (merge with existing entries):

"styles": [
		"node_modules/smart-webcomponents-angular/source/styles/smart.default.css"
	]

Add optional theme CSS from the same package after smart.default.css if you use Bootstrap, Fluent, or other bundled themes.

3 Import the Angular module

Import ValidatorModule from smart-webcomponents-angular/validator: use @Component.imports for standalone, or add it to your AppModule (or feature module) imports array for NgModule apps.

import { ValidatorModule } from 'smart-webcomponents-angular/validator';

4 Root component (standalone)

Add ValidatorModule to your root standalone component (src/app/app.ts). Snippet from Smart UI demos (paths normalized to app.html / App where applicable):

 import { Component, ViewChild, OnInit, AfterViewInit } from '@angular/core';
import { Smart } from 'smart-webcomponents-angular/validator';
import { ButtonComponent } from 'smart-webcomponents-angular/button';
import { CheckBoxComponent } from 'smart-webcomponents-angular/checkbox';
import { DateTimePickerComponent } from 'smart-webcomponents-angular/datetimepicker';
import { DropDownListComponent } from 'smart-webcomponents-angular/dropdownlist';
import { MaskedTextBoxComponent } from 'smart-webcomponents-angular/maskedtextbox';
import { NumericTextBoxComponent } from 'smart-webcomponents-angular/numerictextbox';
import { PasswordTextBoxComponent, PasswordTextBox } from 'smart-webcomponents-angular/passwordtextbox';
import { TextBoxComponent } from 'smart-webcomponents-angular/textbox';

import { ButtonModule } from 'smart-webcomponents-angular/button';

import { CheckBoxModule } from 'smart-webcomponents-angular/checkbox';

import { DateTimePickerModule } from 'smart-webcomponents-angular/datetimepicker';

import { DropDownListModule } from 'smart-webcomponents-angular/dropdownlist';

import { MaskedTextBoxModule } from 'smart-webcomponents-angular/maskedtextbox';

import { NumericTextBoxModule } from 'smart-webcomponents-angular/numerictextbox';

import { PasswordTextBoxModule } from 'smart-webcomponents-angular/passwordtextbox';

import { TextBoxModule } from 'smart-webcomponents-angular/textbox';

import { ValidatorModule } from 'smart-webcomponents-angular/validator';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [ ButtonModule, CheckBoxModule, DateTimePickerModule, DropDownListModule, MaskedTextBoxModule, NumericTextBoxModule, PasswordTextBoxModule, TextBoxModule, ValidatorModule ],
  templateUrl: './app.html',
  styleUrl: './app.css'
})

export class App implements AfterViewInit, OnInit {
    @ViewChild('button', { read: ButtonComponent, static: false }) button!: ButtonComponent;
    @ViewChild('checkbox', { read: CheckBoxComponent, static: false }) checkbox!: CheckBoxComponent;
    @ViewChild('datetimepicker', { read: DateTimePickerComponent, static: false }) datetimepicker!: DateTimePickerComponent;
    @ViewChild('dropdownlist', { read: DropDownListComponent, static: false }) dropdownlist!: DropDownListComponent;
    @ViewChild('maskedtextbox', { read: MaskedTextBoxComponent, static: false }) maskedtextbox!: MaskedTextBoxComponent;
    @ViewChild('numerictextbox', { read: NumericTextBoxComponent, static: false }) numerictextbox!: NumericTextBoxComponent;
    @ViewChild('passwordtextbox', { read: PasswordTextBoxComponent, static: false }) passwordtextbox!: PasswordTextBoxComponent;
    @ViewChild('passwordtextbox2', { read: PasswordTextBoxComponent, static: false }) passwordtextbox2!: PasswordTextBoxComponent;
    @ViewChild('textbox', { read: TextBoxComponent, static: false }) textbox!: TextBoxComponent;
    @ViewChild('textbox2', { read: TextBoxComponent, static: false }) textbox2!: TextBoxComponent;
    @ViewChild('textbox3', { read: TextBoxComponent, static: false }) textbox3!: TextBoxComponent;
    @ViewChild('textbox4', { read: TextBoxComponent, static: false }) textbox4!: TextBoxComponent;


    ngOnInit(): void {
        // onInit code.
    }

    ngAfterViewInit(): void {
        // afterViewInit code.
        this.init();
    }

    init(): void {
        // init code.


        'use strict';
        let maxDate = new Date();
        maxDate.setFullYear(2025);
        const rules = [
            //Email
            { input: '#email-validation', message: 'E-mail is required', action: 'keyup, blur', type: 'required' },
            { input: '#email-validation', message: 'Email is invalid', action: 'keyup', type: 'email' },
            //Password
            { input: '#password-validation', message: 'Password is required!', action: 'keyup, blur', type: 'required' },
            //Confirm password
            { input: '#confirm-password-validation', message: 'Confirm Password is required!', action: 'keyup, blur', type: 'required' },
            {
                input: '#confirm-password-validation', message: '\'Password\' and \'Confirm Password\' do not match.', action: 'keyup, blur', type: 'compare',
                comparisonTarget: function () {
                    let password = document.querySelector('#password-validation') as any;
                    if (password) {
                        return password.value;
                    }
                },
            },
            //Name
            { input: '#name-validation', message: 'Name is required!', action: 'keyup, blur', type: 'required' },
            { input: '#name-validation', message: 'Do not use digits in the Name.', action: 'keyup, blur', type: 'pattern', pattern: /^[^0-9]+$/ },
            { input: '#name-validation', message: 'Name must have at least 2 symbols', action: 'keyup, blur', type: 'stringLength', min: 2 },
            //Date
            //{ input: '#date-validation', message: 'Date of birth is required', action: 'change', type: 'required' },
            { input: '#date-validation', message: 'You must be at least 21 years old', action: 'change', type: 'range', max: maxDate, },
            //Country
            { input: '#country-validation', message: 'Country is required', action: 'change', type: 'required' },
            //City
            { input: '#city-validation', message: 'City is required', action: 'keyup, blur', type: 'required' },
            { input: '#city-validation', message: 'Do not use digits in the City name.', action: 'keyup, blur', type: 'pattern', pattern: /^[^0-9]+$/ },
            { input: '#city-validation', message: 'City must have at least 2 symbols', action: 'keyup, blur', type: 'stringLength', min: 2 },
            //Address
            { input: '#address-validation', message: 'Address is required', action: 'keyup, blur', type: 'required' },
            //Phone
            { input: '#phone-validation', message: 'The phone must have a correct USA phone format', action: 'valuechanged, blur', type: 'pattern', pattern: /^\+\s*1\s*\(\s*[02-9]\d{2}\)\s*\d{3}\s*-\s*\d{4}$/ },
            //Post  code
            { input: '#post-code-validation', message: 'The post code must contains only digits', action: 'change', type: 'numeric' },
            { input: '#post-code-validation', message: 'The post code must have at least 4 symbols', action: 'change', type: 'stringLength', min: 4 },
            //Terms
            { input: '#termsInput', message: 'You must agree to the Terms and Conditions', action: 'change', type: 'required', },
        ];
        //SmartValidator
        const validator = new Smart.Utilities.Validator(rules, '#validationsummary');
        document.querySelector('#register')?.addEventListener('click', () => {
            validator.validate();
        });


    }
}

Boot the app with bootstrapApplication from src/main.ts and an ApplicationConfig in src/app/app.config.ts as generated by the CLI.

5 Template (standalone)

Use your markup in src/app/app.html (or inline template). Bind properties and events on smartValidator as needed:

 <div class="demo-container">
    <form id="testForm" action="./">
        <div class="fieldset">
            <div class="fieldset-header">Credentials</div>
            <div class="field">
                <div class="field-label">Email</div>
                <div class="field-value">
                    <smart-text-box #textbox select-all-on-focus placeholder="Email" id="email-validation"></smart-text-box>
                </div>
            </div>
            <div class="field">
                <div class="field-label">Password</div>
                <div class="field-value">
                    <smart-password-text-box #passwordtextbox select-all-on-focus placeholder="Password"
                    id="password-validation"></smart-password-text-box>
                </div>
            </div>
            <div class="field">
                <div class="field-label">Confirm Password</div>
                <div class="field-value">
                    <smart-password-text-box #passwordtextbox2 select-all-on-focus placeholder="Confirm Password"
                    id="confirm-password-validation"></smart-password-text-box>
                </div>
            </div>
        </div>
        <div class="fieldset clear">
            <div class="fieldset-header">Personal Data</div>
            <div class="field">
                <div class="field-label">Name</div>
                <div class="field-value">
                    <smart-text-box #textbox2 select-all-on-focus placeholder="Name" id="name-validation"></smart-text-box>
                </div>
            </div>
            <div class="field">
                <div class="field-label">Date of birth</div>
                <div class="field-value">
                    <smart-date-time-picker #datetimepicker format-string="dddd, MMM dd, yyyy"
                    calendar-button enable-mouse-wheel-action drop-down-position="bottom" id="date-validation"
                    spin-buttons spin-buttons-position="left"></smart-date-time-picker>
                </div>
            </div>
        </div>
        <div class="fieldset">
            <div class="fieldset-header">Billing address</div>
            <div class="field">
                <div class="field-label">Country</div>
                <div class="field-value">
                    <smart-drop-down-list #dropdownlist id="country-validation">
                        <smart-list-item value="Australia">Australia</smart-list-item>
                        <smart-list-item value="Bulgaria">Bulgaria</smart-list-item>
                        <smart-list-item value="Canada">Canada</smart-list-item>
                    </smart-drop-down-list>
                </div>
            </div>
            <div class="field">
                <div class="field-label">City</div>
                <div class="field-value">
                    <smart-text-box #textbox3 select-all-on-focus placeholder="City" id="city-validation"></smart-text-box>
                </div>
            </div>
            <div class="field">
                <div class="field-label">Address</div>
                <div class="field-value">
                    <smart-text-box #textbox4 select-all-on-focus placeholder="Address" id="address-validation"></smart-text-box>
                </div>
            </div>
            <div class="field">
                <div class="field-label">Phone (optional)</div>
                <div class="field-value">
                    <smart-masked-text-box #maskedtextbox class="material" hint="" mask="+1 (###) ###-####"
                    id="phone-validation"></smart-masked-text-box>
                </div>
            </div>
            <div class="field clear">
                <div class="field-label">Post code (optional)</div>
                <div class="field-value">
                    <smart-numeric-text-box #numerictextbox id="post-code-validation" input-format="integer"
                    min="0" spin-buttons spin-buttons-position="right" spin-buttons-step="1"
                    enable-mouse-wheel-action></smart-numeric-text-box>
                </div>
            </div>
            <div id="check" class="checkbox-validator clear">
                <smart-check-box #checkbox click-mode="press" id="termsInput">Accept terms</smart-check-box>
                <br />
            </div>
        </div>
        <div class="fieldset">
            <div id="registerButton" class="submit-button">
                <smart-button #button id="register" type="button" class="success">Register</smart-button>
            </div>
        </div>
    </form>
    <div id="validationsummary"></div>
</div>

6 NgModule bootstrap (also supported)

Same npm package and angular.json styles as steps 1-2. Put ValidatorModule on your NgModule.imports instead of @Component.imports, and bootstrap with bootstrapModule(AppModule).

The demo sources bundled for this widget use standalone only (there is no app.module.ts in that folder). NgModule is fully supported: put ValidatorModule from smart-webcomponents-angular/validator on NgModule.imports, make your root component non-standalone (remove standalone: true and move widget modules from @Component.imports to the module), and bootstrap with platformBrowserDynamic().bootstrapModule(AppModule).

Minimal main.ts + app.module.ts pairing (adjust paths to match your CLI layout):

src/main.ts

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';

platformBrowserDynamic().bootstrapModule(AppModule).catch((err) => console.error(err));

src/app/app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ValidatorModule } from 'smart-webcomponents-angular/validator';

@NgModule({
	declarations: [ AppComponent ],
	imports: [ BrowserModule, ValidatorModule ],
	bootstrap: [ AppComponent ]
})
export class AppModule { }

Reuse the template and class logic from steps 4-5 in AppComponent, configured for declarations + NgModule.imports instead of a standalone @Component.

Run

ng serve or npm start - then open http://localhost:4200/.

Smart UI for Angular - full documentation

Accessibility

The Validator component follows WAI-ARIA best practices:

  • Keyboard navigation - Tab, Arrow keys, Enter, and Escape are supported
  • ARIA roles - Appropriate roles and labels are applied automatically
  • Focus management - Visible focus indicators for keyboard users
  • Screen readers - State changes are announced to assistive technology
  • High contrast - Supports Windows High Contrast Mode and forced colors

For custom labeling, set aria-label or aria-labelledby attributes on the component.

Live demos

Supported stacks: Smart UI targets Angular 17+, React 18+, Vue 3+, Node 18 LTS, and evergreen browsers; pin exact package versions to your org policy.