Password Input
The password input component provides a secure way for users to enter passwords with built-in visibility controls and clear validation feedback.
import {PasswordInputModule} from "@qualcomm-ui/angular/password-input"Examples
Simple
The simple API bundles all subcomponents together into a single component.
<q-password-input
class="w-72"
clearable
hint="Optional hint"
label="Password"
placeholder="Create password"
/>
Start Icon
Add a startIcon using the prop at the root. Unlike the Text Input, the endIcon is not supported because its slot is reserved for the password visibility trigger.
<q-password-input
class="w-72"
label="Password"
placeholder="Placeholder text"
startIcon="KeyRound"
/>
Child Directives
Provide child directives to customize specific elements while keeping the simple API's default structure.
<q-password-input class="w-72" clearable placeholder="Create password">
<div q-password-input-label>Password</div>
<div q-password-input-hint>Optional hint</div>
</q-password-input>
Composite
Build with the composite API for granular control. This API requires you to provide each subcomponent, but gives you full control over the structure and layout.
<div class="w-72" q-password-input-root>
<label q-password-input-label>Label</label>
<div q-password-input-input-group>
<input placeholder="Placeholder text" q-password-input-input />
<button q-password-input-clear-trigger></button>
<button q-password-input-visibility-trigger></button>
<span q-password-input-error-indicator></span>
</div>
<div q-password-input-error-text>Error text</div>
<div q-password-input-hint>Optional hint</div>
</div>
Controlled Visibility
Set the initial visibility using the defaultVisible prop, or use visible and visibleChanged to control the visibility manually. These props follow our controlled state pattern.
import {Component, signal} from "@angular/core"
import {ButtonModule} from "@qualcomm-ui/angular/button"
import {PasswordInputModule} from "@qualcomm-ui/angular/password-input"
@Component({
imports: [PasswordInputModule, ButtonModule],
selector: "password-input-controlled-visibility-demo",
template: `
<div class="flex flex-col gap-4">
<q-password-input
class="w-72"
defaultValue="passw0rd"
label="Password"
placeholder="Enter your password"
[visible]="visible()"
(visibleChanged)="setVisible($event)"
/>
<button
emphasis="primary"
q-button
variant="outline"
(click)="toggleVisible()"
>
{{ visible() ? "Hide Password" : "Show Password" }}
</button>
</div>
`,
})
export class PasswordInputControlledVisibilityDemo {
protected readonly visible = signal(false)
setVisible(visible: boolean) {
this.visible.set(visible)
}
toggleVisible() {
this.visible.update((visible) => !visible)
}
}Error Text and Indicator
Provide a custom error message using the errorText prop.
For template-driven forms, the error text and indicator will only render when invalid is true.
<q-password-input
#passwordInput
class="w-64"
errorText="You must enter your password"
label="Label"
placeholder="Enter your password"
required
[invalid]="!value()"
[(ngModel)]="value"
/>
Forms
Control and validate the input value using Angular form control bindings.
Template Forms
When using template-driven forms with ngModel, perform validation manually in your component and pass the result to the invalid property.
TIP
Form validation timing is controlled by the updateOn property on the form control.
<q-password-input
class="w-72"
label="Required"
placeholder="Enter a value"
[errorText]="errorText()"
[invalid]="!!errorText()"
[(ngModel)]="value"
/>
Required
When using template forms, pass the required property to apply the RequiredValidator to the form control.
<q-password-input
class="w-72"
label="Required"
placeholder="Enter a value"
required
[(ngModel)]="value"
/>
Reactive Forms
Use Reactive Forms for better control of form state and validation.
- We provide default error messages for every built-in validator, so you can omit the errorText prop when using Reactive Forms.
- We also look for the
erroranderrorTextproperties on custom validators. If you provide a custom validator, use one of these properties to provide error messages automatically when the field is invalid:
import {Component, inject} from "@angular/core"
import {
type AbstractControl,
FormBuilder,
type FormGroup,
ReactiveFormsModule,
type ValidationErrors,
type ValidatorFn,
} from "@angular/forms"
import {ButtonModule} from "@qualcomm-ui/angular/button"
import {PasswordInputModule} from "@qualcomm-ui/angular/password-input"
function passwordValidator(): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
const password = control.value
if (!password || password.trim().length === 0) {
return {error: "Please enter your password"}
}
if (password.length < 8) {
return {error: "Must be at least 8 characters long"}
}
if (!/(?=.*[a-z])/.test(password)) {
return {error: "Must contain at least one lowercase letter"}
}
if (!/(?=.*[A-Z])/.test(password)) {
return {error: "Must contain at least one uppercase letter"}
}
if (!/(?=.*\d)/.test(password)) {
return {error: "Must contain at least one number"}
}
if (!/(?=.*[@$!%*?&])/.test(password)) {
return {error: "Must contain at least one special character (@$!%*?&)"}
}
return null
}
}
function confirmPasswordValidator(passwordControlName: string): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
if (!control.parent) {
return null
}
const password = control.parent.get(passwordControlName)?.value
const confirmPassword = control.value
if (!confirmPassword || confirmPassword.trim().length === 0) {
return {error: "Please confirm your password"}
}
if (confirmPassword !== password) {
return {error: "Passwords do not match"}
}
return null
}
}
@Component({
imports: [ReactiveFormsModule, ButtonModule, PasswordInputModule],
selector: "password-input-reactive-forms-demo",
template: `
<form
class="mx-auto flex w-full max-w-xs flex-col gap-3"
[formGroup]="form"
(ngSubmit)="onSubmit()"
>
<div class="grid grid-cols-1 gap-4">
<q-password-input
#passwordField
formControlName="password"
label="Password"
placeholder="Create password"
[hint]="
passwordField.isInvalid()
? null
: 'must be 8+ characters with at least 1 number, lowercase, uppercase, and special character.'
"
/>
<q-password-input
formControlName="confirmPassword"
label="Confirm password"
placeholder="Confirm password"
/>
</div>
<div class="mt-2 flex w-full justify-end">
<button
emphasis="primary"
q-button
type="submit"
variant="fill"
[disabled]="isSubmitting"
>
Submit
</button>
</div>
</form>
`,
})
export class PasswordInputReactiveFormsDemo {
form: FormGroup
submissionAttempts = 0
isSubmitting = false
private fb = inject(FormBuilder)
constructor() {
this.form = this.fb.group({
confirmPassword: ["", [confirmPasswordValidator("password")]],
password: ["", {validators: [passwordValidator()]}],
})
}
onSubmit(): void {
this.submissionAttempts++
if (this.form.valid) {
this.isSubmitting = true
console.log("Form submitted:", this.form.value)
}
}
}Provide the FORM_CONTROL_ERROR_MESSAGE_PROVIDER token to override the default error messages.
import {
FORM_CONTROL_ERROR_MESSAGE_PROVIDER,
type FormControlKnownErrors,
} from "@qualcomm-ui/angular-core/input"
@Directive({
providers: [
{
provide: FORM_CONTROL_ERROR_MESSAGE_PROVIDER,
useValue: {
email: () => "Please provide a valid email address",
} satisfies FormControlKnownErrors,
},
],
})
export class MyDirective {}The defaults are as follows:
const defaultKnownErrors: FormControlKnownErrors = {
email: () => "Invalid email",
max: (err) => `Max: ${err.max}`,
maxLength: (err) => `Max length: ${err.maxLength}`,
min: (err) => `Min: ${err.min}`,
minLength: (err) => `Min length: ${err.requiredLength}`,
pattern: () => "Invalid format",
required: () => "This field is required",
requiredTrue: () => "This field is required",
}State Guidelines
The disabled, invalid, and required properties have no effect when using Reactive Forms. Use the equivalent Reactive Form bindings instead:
disabledField = new FormControl("")
invalidField = new FormControl("", {
validators: [Validators.required],
})
requiredField = new FormControl("", {validators: [Validators.required]})
Explorer
Component Anatomy
Hover to highlight, click to view API
API
<q-password-input>
The <q-password-input> component extends the q-password-input-root directive with the following properties:
stringstringbooleantrue, renders a clear button that resets the input value on click.
The button only appears when the input has a value.string<div q-text-input-error-text>...</div>
string<div q-text-input-hint>...</div>
string<div q-text-input-label>...</div>
stringComposite API
q-password-input-root
| 'current-password'
| 'new-password'
stringboolean'ltr' | 'rtl'
boolean() =>
| Node
| ShadowRoot
| Document
booleanstringbooleanboolean| 'sm'
| 'md'
| 'lg'
| string
| LucideIconData
<div q-password-input-input-group>
<div q-input-start-icon [icon]="..."></div>
</div>
{
visibilityTrigger?: (
visible: boolean,
) => string
}
booleanstringbooleanclass'qui-input__root'data-disableddata-focusdata-invaliddata-password-input-part'root'data-size| 'sm'
| 'md'
| 'lg'
q-password-input-input-group
class'qui-input__input-group'data-disableddata-focusdata-invaliddata-password-input-part'input-group'data-readonlydata-size| 'sm'
| 'md'
| 'lg'
q-password-input-label
stringclass'qui-input__label'data-disableddata-focusdata-invaliddata-password-input-part'label'data-size| 'sm'
| 'md'
| 'lg'
q-password-input-hint
stringclass'qui-input__hint'data-disableddata-password-input-part'hint'hiddenbooleanq-password-input-clear-trigger
class'qui-input__clear-trigger'data-disableddata-password-input-part'clear-trigger'data-size| 'sm'
| 'md'
| 'lg'
q-password-input-input
string[attr.aria-label]stringstringclass'qui-input__input'data-emptydata-focusdata-invaliddata-password-input-part'input'data-readonlydata-size| 'sm'
| 'md'
| 'lg'
data-state| 'hidden'
| 'visible'
q-password-input-error-text
| string
| LucideIconData
stringclass'qui-input__error-text'data-password-input-part'error-text'hiddenbooleanq-password-input-error-indicator
| LucideIconData
| string
class'qui-input__error-indicator'data-password-input-part'error-indicator'data-size| 'sm'
| 'md'
| 'lg'
hiddenboolean