Signature Pad
A signature capture field — Kendo's and Syncfusion's Signature: draw with a mouse, pen or finger and the strokes are smoothed into curves whose width follows the pen speed. The value is a data: URL of the signature (PNG, or SVG that also carries the strokes so a stored value restores an editable pad).
Type is the keyboard-accessible alternative: a real labelled text field whose text is rendered in a script font into the same export. Works standalone via [(value)], with Signal Forms via [formField], and with reactive/template forms via formControl/ngModel.
Getting started
Draw on the surface; each pen-up commits a PNG data: URL. Undo (or Ctrl+Z while focus is in the pad) removes the last stroke, Escape mid-stroke cancels it, Clear empties the pad. Strokes are stored surface-relative, so resizing redraws the same signature.
Strokes: 0 · signed: false
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { OgeSignaturePad } from '@oge-ui/inputs';
@Component({
selector: 'demo-root',
imports: [OgeSignaturePad],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<!-- Draw with a mouse, pen or finger. The value is a data: URL (PNG by
default); Undo (or Ctrl+Z) removes the last stroke, Escape mid-stroke
cancels it. -->
<oge-signature-pad
label="Customer signature"
[(value)]="signature"
(strokeEnded)="strokes.set($event.strokeCount)"
/>
<p>Strokes: {{ strokes() }} · signed: {{ signature() !== null }}</p>
`,
})
export class Demo {
protected readonly signature = signal<string | null>(null);
protected readonly strokes = signal(0);
}Typed signature
The keyboard alternative (WCAG 2.1.1): Type switches to a labelled text field, and the name is rendered in fontFamily into the same export. [(mode)] is two-way; allowTyping hides the switch.
Mode: type · signed: false
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { OgeSignaturePad } from '@oge-ui/inputs';
import type { OgeSignatureMode } from '@oge-ui/inputs';
@Component({
selector: 'demo-root',
imports: [OgeSignaturePad],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<!-- The keyboard-accessible alternative: Type renders a name in a
script font into the same export. [(mode)] is two-way. -->
<oge-signature-pad
label="Typed signature"
fontFamily="'Segoe Script', 'Brush Script MT', cursive"
[(mode)]="mode"
[(value)]="signature"
/>
`,
})
export class Demo {
protected readonly mode = signal<OgeSignatureMode>('type');
protected readonly signature = signal<string | null>(null);
}SVG and pen options
format="svg" exports vector paths and embeds the strokes, so writing a stored value back restores an editable pad. minWidth/maxWidth bound the speed-weighted width, strokeColor and backgroundColor set the ink and the baked-in background, height the surface.
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { OgeSignaturePad } from '@oge-ui/inputs';
import { OgeButton } from '@oge-ui/buttons';
@Component({
selector: 'demo-root',
imports: [OgeSignaturePad, OgeButton],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<!-- format="svg" exports vector paths and embeds the strokes, so a
stored value restores an editable pad. The width follows the pen speed
between minWidth and maxWidth. -->
<oge-signature-pad
#pad
label="Approval"
format="svg"
strokeColor="#1d4ed8"
backgroundColor="#ffffff"
[minWidth]="1.5"
[maxWidth]="4.5"
[height]="140"
[(value)]="svg"
/>
<oge-button text="Save" (clicked)="saved = pad.toDataUrl('svg')" />
<oge-button text="Restore saved" (clicked)="svg.set(saved)" />
`,
})
export class Demo {
protected readonly svg = signal<string | null>(null);
protected saved: string | null = null;
}Inside a form
A FormValueControl and a ControlValueAccessor. A finished stroke marks the control touched, so required shows once the signer has tried; reset() empties the pad.
Valid: false
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { OgeSignaturePad } from '@oge-ui/inputs';
import { OgeButton } from '@oge-ui/buttons';
import { ReactiveFormsModule, FormControl, Validators } from '@angular/forms';
@Component({
selector: 'demo-root',
imports: [OgeSignaturePad, OgeButton, ReactiveFormsModule],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<!-- A FormValueControl and a ControlValueAccessor: formControl, ngModel
and [formField] bind it. A stroke marks it touched; reset() empties it. -->
<oge-signature-pad label="Signature" [formControl]="sign" />
<p>Valid: {{ sign.valid }}</p>
<oge-button text="Reset" (clicked)="sign.reset()" />
`,
})
export class Demo {
protected readonly sign = new FormControl<string | null>(null, [
Validators.required,
]);
}