Documentation
FastAnn is a production-ready UI annotation library. Add contextual comments, badges, and highlights to any DOM element in minutes.
Installation
Install the framework-agnostic core and the wrapper for your stack:
# Angular
npm install @fastann/core @fastann/angular
# React
npm install @fastann/core @fastann/react
# Vue
npm install @fastann/core @fastann/vue
# jQuery
npm install @fastann/core @fastann/jquery
Quick Start
Bootstrap the library in your Angular application:
// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideAnnotation } from '@fastann/angular';
export const appConfig: ApplicationConfig = {
providers: [
provideAnnotation({
apiUrl: 'https://api.yourapp.com',
licenseKey: 'YOUR_PRO_LICENSE_KEY', // Pro only
}),
],
};
Configuration
| Option | Type | Required | Description |
|---|---|---|---|
apiUrl | string | Yes | Base URL for the annotation API. |
licenseKey | string | Pro | RSA-signed domain-locked key. |
theme | 'light' | 'dark' | No | Default: 'light' |
locale | string | No | Default: 'en' |
Cell Keys
A cell key is a unique string that identifies an annotatable element. It follows the format rowId:columnId:
<td ann-cell-key="row-42:revenue">{{ "{{" }} row.revenue {{ "}}" }}</td>
Keys must be stable across page loads — use your data's primary key, not a loop index.
Permissions
FastAnn uses a granular permission model. Assign permissions per user:
type Permission =
| 'view_annotation' // see annotation badges
| 'create_annotation' // add new annotations
| 'edit_annotation' // edit own annotations
| 'delete_annotation' // delete own annotations
| 'view_comment' // read comments
| 'create_comment' // post comments
| 'delete_comment' // delete any comment (moderator)
| 'view_logs'; // view change history
Angular Guide
Import AnnCellDirective into your standalone component:
// sales-table.component.ts
import { AnnCellDirective } from '@fastann/angular';
@Component({
standalone: true,
imports: [AnnCellDirective],
template: `
<table>
<tr *ngFor="let row of rows">
<td [ann-cell-key]="'r' + row.id + ':name'">{{ "{{" }} row.name {{ "}}" }}</td>
<td [ann-cell-key]="'r' + row.id + ':sales'">{{ "{{" }} row.sales {{ "}}" }}</td>
</tr>
</table>
`
})
export class SalesTableComponent {
rows = [...];
}
React Guide
// SalesTable.tsx
import { AnnCell, AnnProvider } from '@fastann/react';
export function SalesTable() {
return (
<AnnProvider apiUrl="https://api.yourapp.com" licenseKey={LICENSE_KEY}>
<table>
{rows.map(row => (
<tr key={row.id}>
<AnnCell cellKey={`r${row.id}:name`}>{row.name}</AnnCell>
<AnnCell cellKey={`r${row.id}:sales`}>{row.sales}</AnnCell>
</tr>
))}
</table>
</AnnProvider>
);
}
Vue Guide
<!-- SalesTable.vue -->
<script setup>
import { AnnCell } from '@fastann/vue';
</script>
<template>
<table>
<tr v-for="row in rows" :key="row.id">
<ann-cell :cell-key="`r${row.id}:name`">{{ "{{" }} row.name {{ "}}" }}</ann-cell>
</tr>
</table>
</template>
License Key Format
A Pro license key is structured as:
Base64(UTF8(payloadJson)) . Base64(RSA_PKCS1_SHA256_signature)
Where the payload JSON is:
{ "dom": "yoursite.com", "plan": "Pro", "uid": "a1b2c3d4" }
Frontend Verification
Use the Web Crypto API to verify licenses entirely offline:
export async function verifyLicense(licenseKey: string): Promise<boolean> {
const [payloadB64, sigB64] = licenseKey.split('.');
if (!payloadB64 || !sigB64) return false;
const payloadBytes = Uint8Array.from(atob(payloadB64), c => c.charCodeAt(0));
const sigBytes = Uint8Array.from(atob(sigB64), c => c.charCodeAt(0));
const cryptoKey = await crypto.subtle.importKey(
'spki', pemToArrayBuffer(PUBLIC_KEY_PEM),
{ name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' },
false, ['verify']
);
const valid = await crypto.subtle.verify(
'RSASSA-PKCS1-v1_5', cryptoKey, sigBytes, payloadBytes
);
if (!valid) return false;
const payload = JSON.parse(new TextDecoder().decode(payloadBytes));
return payload.dom === window.location.hostname.toLowerCase();
}