Skip to content

@absoluteui/core

Configuration, dates and time zones, recurrence, internationalization, sanitization, errors, and DOM helpers shared by every component.

import { ... } from '@absoluteui/core';

The engines every component builds on: validated global configuration, date and time zone values, recurrence rules, translated messages, HTML sanitization, and the shared error model. Your application uses the same functions for its own screens. Configuration, Dates and time zones, and Internationalization cover each area in depth.

How do I set the locale and time zone for the whole application?

Section titled “How do I set the locale and time zone for the whole application?”

Call configureAbsoluteUI once at startup; components already on the page update in place. Each call replaces the whole global layer, so pass every setting you want to keep.

import { configureAbsoluteUI, getCommonConfig, onConfigChange } from '@absoluteui/core';
let changes = 0;
const stop = onConfigChange(() => {
changes += 1;
});
configureAbsoluteUI({ common: { locale: 'en-IN', timezone: 'Asia/Kolkata', density: 'compact' } });
[getCommonConfig().timezone, getCommonConfig().density]; // => ['Asia/Kolkata', 'compact']
changes; // => 1
stop();

How do I turn a local shift start into an exact instant?

Section titled “How do I turn a local shift start into an exact instant?”

A shift that starts at 09:00 in Bengaluru is a wall-clock time; toInstant fixes it to a moment for storage or APIs. Check getLocalTimeStatus where daylight saving can make a local time skip or repeat.

import { getLocalTimeStatus, instantToString, plainDate, plainDateTime, plainTime, toInstant } from '@absoluteui/core';
const shiftStart = plainDateTime(plainDate(2026, 10, 5), plainTime(9, 0));
instantToString(toInstant(shiftStart, 'Asia/Kolkata')); // => '2026-10-05T03:30:00.000Z'
getLocalTimeStatus(plainDateTime(plainDate(2026, 3, 8), plainTime(2, 30)), 'America/New_York'); // => 'nonexistent'

How do I schedule a job on the last weekday of each month?

Section titled “How do I schedule a job on the last weekday of each month?”

Build an RFC 5545 rule with recurrenceRule: weekdays only, last position in the month. expandRecurrence lists the dates; describeRecurrence gives a sentence for the UI.

import { describeRecurrence, expandRecurrence, plainDate, plainDateToString, recurrenceRule, recurrenceRuleToString } from '@absoluteui/core';
const payroll = recurrenceRule({
frequency: 'monthly',
byDay: [{ weekday: 1 }, { weekday: 2 }, { weekday: 3 }, { weekday: 4 }, { weekday: 5 }],
bySetPos: [-1],
count: 3,
});
expandRecurrence(payroll, plainDate(2026, 10, 30)).map((o) => (o.start.kind === 'PlainDate' ? plainDateToString(o.start) : null)); // => ['2026-10-30', '2026-11-30', '2026-12-31']
recurrenceRuleToString(payroll); // => 'RRULE:FREQ=MONTHLY;COUNT=3;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1'
describeRecurrence(payroll, { locale: 'en' }); // => 'Every month on Monday, Tuesday, Wednesday, Thursday, and Friday (the last of them), 3 times'

A recurrence rule knows weekdays, not holidays. For payroll on the last working day, ask a business calendar, which also knows the company’s holidays (see Business calendars):

import { createBusinessCalendar, fixedHoliday, lastBusinessDayOfMonth } from '@absoluteui/helpers/business-calendar';
const company = createBusinessCalendar({ holidays: [fixedHoliday('Year-end closure', 12, 31)] });
lastBusinessDayOfMonth(2026, 12, company); // => '2026-12-30' // the rule above gives 2026-12-31
lastBusinessDayOfMonth(2026, 10, company); // => '2026-10-30'

How do I translate my own application’s messages?

Section titled “How do I translate my own application’s messages?”

Register a catalog per locale under your own namespace. getMessage falls back from region to language to English and fills {name} placeholders.

import { getMessage, registerMessages } from '@absoluteui/core';
registerMessages('leave', 'en', { submitted: 'Leave request {id} submitted for approval.' });
registerMessages('leave', 'de', { submitted: 'Urlaubsantrag {id} zur Genehmigung eingereicht.' });
getMessage('leave', 'submitted', { id: 'LR-1042' }, 'de-AT'); // => 'Urlaubsantrag LR-1042 zur Genehmigung eingereicht.'
getMessage('leave', 'submitted', { id: 'LR-1042' }, 'fr-FR'); // => 'Leave request LR-1042 submitted for approval.'

Never assign untrusted HTML to innerHTML. setSanitizedHtml parses it inertly and rebuilds only allowlisted elements, attributes, and URL schemes. See Security and CSP.

import { setSanitizedHtml } from '@absoluteui/core';
const note = document.createElement('div');
setSanitizedHtml(note, '<p>Approved by <strong>Asha</strong><img src="x" onerror="alert(1)"></p><a href="javascript:alert(1)">details</a>');
note.innerHTML; // => '<p>Approved by <strong>Asha</strong></p><a>details</a>'

How do I emit events and clean up in my own widget?

Section titled “How do I emit events and clean up in my own widget?”

emit dispatches a standard CustomEvent and returns false when a cancelable event was prevented. DisposableGroup collects listeners and other cleanup and runs them once, in reverse order.

import { DisposableGroup, createId, emit } from '@absoluteui/core';
const card = document.createElement('section');
card.id = createId('leave-card');
const cleanup = new DisposableGroup();
cleanup.listen(card, 'click', () => {
emit(card, 'leave-open', { id: 'LR-1042' });
});
card.addEventListener('leave-withdraw', (event) => {
event.preventDefault();
});
emit(card, 'leave-withdraw', { id: 'LR-1042' }, { cancelable: true }); // => false
cleanup.dispose();
cleanup.disposed; // => true

Everything throws an AbsoluteUIError with a stable code and a category (configuration, validation, runtime). Branch on the code, not the message; messages never contain the value you passed. Set diagnostics: 'development' while developing for remediation hints.

import { configureAbsoluteUI, getMessage, plainDate, plainDateTime, plainTime, recurrenceRule, toInstant } from '@absoluteui/core';
configureAbsoluteUI({ common: { timezone: 'Mars/Olympus' } }); // => throws CFG_INVALID_VALUE
getMessage('leave', 'no-such-key'); // => throws I18N_MISSING_MESSAGE
recurrenceRule({ frequency: 'weekly', count: 5, until: plainDate(2026, 12, 31) }); // => throws RECURRENCE_INVALID
toInstant(plainDateTime(plainDate(2026, 3, 8), plainTime(2, 30)), 'America/New_York', 'reject'); // => throws TZ_NONEXISTENT_TIME

validators

namespace validators {
function oneOf<const T extends readonly (string | number | boolean)[]>(values: T): Guard<T[number]>;
function integerInRange(min: number, max: number): Guard<number>;
function numberInRange(min: number, max: number): Guard<number>;
function nullable<T>(guard: Guard<T>): Guard<T | null>;
function isRecord(v: unknown): v is Record<string, unknown>;
type Guard<T> = (value: unknown) => value is T;
const isBoolean: Guard<boolean>;
const isString: Guard<string>;
const isNonEmptyString: Guard<string>;
const isLocale: Guard<string>;
const isTimeZone: Guard<string>;
}

configureAbsoluteUI

Replace the global configuration layer. Validation is atomic: on error, the previous configuration remains active.

function configureAbsoluteUI(input: GlobalConfigInput): void;

defineComponentConfig

Register a component’s configuration schema. inherits lists common options the component honors; they can be overridden per component and per instance.

function defineComponentConfig<T extends object, const I extends keyof CommonConfig = never>(name: string, schema: ConfigSchema<T>, inherits?: readonly I[]): ComponentConfigHandle<T & Pick<CommonConfig, I>>;

describeComponentConfig

Option names of a registered component configuration, or undefined when name is not registered.

function describeComponentConfig(name: string): {
readonly optionNames: readonly string[];
readonly inheritedOptionNames: readonly string[];
} | undefined;

getCommonConfig

Resolved common configuration.

function getCommonConfig(): Readonly<CommonConfig>;

normalizeConfig

Validate a configuration input (Mode A or B) without applying it. Throws the same errors as configureAbsoluteUI. Framework integrations use it for scoped configuration that must never touch the page-global layer (for example per-request server rendering).

function normalizeConfig(input: GlobalConfigInput): NormalizedConfig;

onConfigChange

Subscribe to any global/theme configuration change. Returns an unsubscribe function.

function onConfigChange(listener: () => void): () => void;

resetAbsoluteUIConfig

Reset all configuration layers. Intended for tests and full application teardown.

function resetAbsoluteUIConfig(): void;

commonSchema

const commonSchema: ConfigSchema<CommonConfig>;

CommonConfig

Settings shared by all components.

interface CommonConfig {
locale: string;
timezone: string;
density: Density;
direction: Direction;
animation: AnimationMode;
theme: string;
disambiguation: Disambiguation;
diagnostics: DiagnosticsMode;
timeZoneEngine: TimeZoneEngine | null;
}

ComponentConfigHandle

interface ComponentConfigHandle<R> {
readonly name: string;
readonly optionNames: readonly string[];
readonly inheritedOptionNames: readonly string[];
resolve(instance?: Partial<R>): Readonly<R>;
assertUpdatable(previous: Partial<R>, next: Partial<R>): void;
subscribe(listener: () => void): () => void;
}

ComponentConfigMap

Component configuration registry. Components augment this interface:

declare module '@absoluteui/core' {
interface ComponentConfigMap { dialog: DialogConfig }
}
interface ComponentConfigMap {
}

NormalizedConfig

Validated configuration layer returned by normalizeConfig.

interface NormalizedConfig {
readonly common: Partial<CommonConfig>;
readonly components: ComponentConfigInput;
}

OptionSpec

interface OptionSpec<T> {
readonly default: T;
readonly expected: string;
readonly validate: Guard<T>;
readonly mutability?: Mutability;
}

StructuredConfigInput

Mode B: common and component-specific settings.

interface StructuredConfigInput {
common?: Partial<CommonConfig>;
components?: ComponentConfigInput;
}

AnimationMode

type AnimationMode = 'none' | 'subtle';

ComponentConfigInput

type ComponentConfigInput = {
[K in keyof ComponentConfigMap]?: Partial<ComponentConfigMap[K]>;
};

ConfigSchema

type ConfigSchema<T> = {
readonly [K in keyof T]-?: OptionSpec<T[K]>;
};

Density

type Density = 'compact' | 'comfortable' | 'spacious';

Direction

type Direction = 'ltr' | 'rtl';

Disambiguation

type Disambiguation = 'compatible' | 'earlier' | 'later' | 'reject';

GlobalConfigInput

Mode A (flat common settings) or Mode B (structured).

type GlobalConfigInput = Partial<CommonConfig> | StructuredConfigInput;

Guard

Reusable option validators. Each returns a type guard and never inspects values beyond type/range checks.

type Guard<T> = (value: unknown) => value is T;

Mutability

type Mutability = 'dynamic' | 'init-only';

addDays

function addDays(date: PlainDate, days: number): PlainDate;

addMonths

Adds calendar months, clamping the day to the target month’s length.

function addMonths(date: PlainDate, months: number): PlainDate;

comparePlainDate

function comparePlainDate(a: PlainDate, b: PlainDate): -1 | 0 | 1;

comparePlainYearMonth

function comparePlainYearMonth(a: PlainYearMonth, b: PlainYearMonth): -1 | 0 | 1;

comparePlainYearQuarter

function comparePlainYearQuarter(a: PlainYearQuarter, b: PlainYearQuarter): -1 | 0 | 1;

dayOfWeek

ISO weekday: 1 = Monday … 7 = Sunday.

function dayOfWeek(date: PlainDate): number;

daysInMonth

function daysInMonth(year: number, month: number): number;

duration

function duration(milliseconds: number): Duration;

durationToString

ISO 8601 duration of a fixed-length Duration, in hours, minutes, and seconds (PT1H30M, PT36H, PT0.25S, PT0S). Days are never emitted, because an ISO day is a calendar day that is not always 24 hours long. Negative durations use the ISO 8601-2 leading minus (-PT5M).

function durationToString(value: Duration): string;

fieldsToEpoch

UTC epoch milliseconds for wall-clock fields, correct for years 0-99 and negative years.

function fieldsToEpoch(year: number, month: number, day: number, hour?: number, minute?: number, second?: number, millisecond?: number): number;

formatOffset

Offset string such as “+05:30” for an instant in a zone.

function formatOffset(value: Instant, timeZone: string, engine?: TimeZoneEngine): string;

getLocalTimeStatus

function getLocalTimeStatus(value: PlainDateTime, timeZone: string, engine?: TimeZoneEngine): LocalTimeStatus;

getPossibleInstants

All instants at which the wall-clock time occurs in the zone: one (exact), two (ambiguous, clock fell back) or none (nonexistent, clock sprang forward).

function getPossibleInstants(value: PlainDateTime, timeZone: string, engine?: TimeZoneEngine): Instant[];

getTimeZoneEngine

Active engine: configured resolver or the built-in Intl engine.

function getTimeZoneEngine(): TimeZoneEngine;

instant

function instant(epochMilliseconds: number): Instant;

instantToString

function instantToString(value: Instant): string;

isLeapYear

function isLeapYear(year: number): boolean;

now

Current instant. Isolated for testability; components never read the host timezone.

function now(): Instant;

parseDuration

Strict ISO 8601 duration with day, hour, minute, and second designators (P1DT2H, PT90M, PT1.5S), as a fixed-length Duration. A day counts as exactly 24 hours. Years, months, and weeks are calendar units and are rejected, as are empty designators (P, PT). Returns null when invalid.

function parseDuration(text: string): Duration | null;

parseInstant

Strict ISO 8601 instant; requires Z or an explicit offset. Returns null when invalid.

function parseInstant(text: string): Instant | null;

parsePlainDate

Strict ISO 8601 calendar date (YYYY-MM-DD). Returns null when invalid.

function parsePlainDate(text: string): PlainDate | null;

parsePlainTime

Strict ISO 8601 time (HH:MM[:SS[.sss]]). Returns null when invalid.

function parsePlainTime(text: string): PlainTime | null;

parsePlainYearMonth

Strict ISO 8601 year and month (YYYY-MM). Returns null when invalid.

function parsePlainYearMonth(text: string): PlainYearMonth | null;

parsePlainYearQuarter

Strict YYYY-Qn. Returns null when invalid.

function parsePlainYearQuarter(text: string): PlainYearQuarter | null;

plainDate

function plainDate(year: number, month: number, day: number): PlainDate;

plainDatesEqual

function plainDatesEqual(a: PlainDate | null, b: PlainDate | null): boolean;

plainDateTime

function plainDateTime(date: PlainDate, time?: PlainTime): PlainDateTime;

plainDateToString

function plainDateToString(date: PlainDate): string;

plainTime

function plainTime(hour: number, minute?: number, second?: number, millisecond?: number): PlainTime;

plainTimeToString

function plainTimeToString(time: PlainTime): string;

plainYearMonth

function plainYearMonth(year: number, month: number): PlainYearMonth;

plainYearMonthToString

ISO 8601 YYYY-MM.

function plainYearMonthToString(value: PlainYearMonth): string;

plainYearQuarter

function plainYearQuarter(year: number, quarter: number): PlainYearQuarter;

plainYearQuarterToString

YYYY-Qn (the ISO 8601-2 quarter notation used by most reporting tools).

function plainYearQuarterToString(value: PlainYearQuarter): string;

toInstant

Convert a wall-clock time in a zone to an exact instant.

Case compatible earlier later reject
ambiguous earlier instant earlier instant later instant error
nonexistent shift forward by gap shift backward by gap shift forward by gap error
function toInstant(value: PlainDateTime, timeZone: string, disambiguation?: Disambiguation, engine?: TimeZoneEngine): Instant;

toPlainDateTime

Wall-clock time of an instant in a zone.

function toPlainDateTime(value: Instant | ZonedDateTime, timeZone?: string, engine?: TimeZoneEngine): PlainDateTime;

zonedDateTime

function zonedDateTime(value: Instant, timeZone: string, engine?: TimeZoneEngine): ZonedDateTime;

intlTimeZoneEngine

const intlTimeZoneEngine: TimeZoneEngine;

Duration

A fixed-length duration in milliseconds (not a calendar duration such as “1 month”).

interface Duration {
readonly kind: 'Duration';
readonly milliseconds: number;
}

Instant

An exact point on the UTC timeline.

interface Instant {
readonly kind: 'Instant';
readonly epochMilliseconds: number;
}

PlainDate

interface PlainDate {
readonly kind: 'PlainDate';
readonly year: number;
readonly month: number;
readonly day: number;
}

PlainDateTime

interface PlainDateTime {
readonly kind: 'PlainDateTime';
readonly date: PlainDate;
readonly time: PlainTime;
}

PlainTime

interface PlainTime {
readonly kind: 'PlainTime';
readonly hour: number;
readonly minute: number;
readonly second: number;
readonly millisecond: number;
}

PlainYearMonth

A calendar month without a day (ISO 8601 YYYY-MM).

interface PlainYearMonth {
readonly kind: 'PlainYearMonth';
readonly year: number;
readonly month: number;
}

PlainYearQuarter

A calendar quarter (YYYY-Qn): Q1 is January to March, Q4 October to December.

interface PlainYearQuarter {
readonly kind: 'PlainYearQuarter';
readonly year: number;
readonly quarter: number;
}

Range

Inclusive range of comparable values.

interface Range<T> {
readonly start: T;
readonly end: T;
}

TimeZoneEngine

interface TimeZoneEngine {
getOffsetMs(epochMilliseconds: number, timeZone: string): number;
isValidTimeZone(timeZone: string): boolean;
}

ZonedDateTime

An exact instant observed in a specific IANA timezone.

interface ZonedDateTime {
readonly kind: 'ZonedDateTime';
readonly epochMilliseconds: number;
readonly timeZone: string;
}

LocalTimeStatus

type LocalTimeStatus = 'exact' | 'ambiguous' | 'nonexistent';

createId

Unique, deterministic-per-page element id.

function createId(prefix?: string): string;

emit

Dispatch a standards-based CustomEvent from a host element. Returns false when a cancelable event was prevented.

function emit(host: EventTarget, type: string, detail: unknown, options?: EmitOptions): boolean;

DisposableGroup

Collects cleanup callbacks and runs them once, in reverse order.

class DisposableGroup {
add(disposer: Disposer): void;
listen<K extends keyof HTMLElementEventMap>(target: HTMLElement, type: K, handler: (event: HTMLElementEventMap[K]) => void, options?: AddEventListenerOptions): void;
listen<K extends keyof DocumentEventMap>(target: Document, type: K, handler: (event: DocumentEventMap[K]) => void, options?: AddEventListenerOptions): void;
listen<K extends keyof WindowEventMap>(target: Window, type: K, handler: (event: WindowEventMap[K]) => void, options?: AddEventListenerOptions): void;
get disposed(): boolean;
dispose(): void;
}

EmitOptions

interface EmitOptions {
cancelable?: boolean;
bubbles?: boolean;
}

Disposer

type Disposer = () => void;

configurationError

function configurationError(code: string, summary: string, details?: ErrorDetails): AbsoluteUIError;

getDiagnosticsMode

function getDiagnosticsMode(): DiagnosticsMode;

runtimeError

function runtimeError(code: string, summary: string, details?: ErrorDetails): AbsoluteUIError;

validationError

function validationError(code: string, summary: string, details?: ErrorDetails): AbsoluteUIError;

AbsoluteUIError

class AbsoluteUIError extends Error {
readonly name = "AbsoluteUIError";
readonly category: ErrorCategory;
readonly code: string;
readonly details: ErrorDetails;
constructor(category: ErrorCategory, code: string, summary: string, details?: ErrorDetails);
}

ErrorDetails

interface ErrorDetails {
readonly component?: string;
readonly property?: string;
readonly expected?: string;
readonly remediation?: string;
}

DiagnosticsMode

type DiagnosticsMode = 'production' | 'development';

ErrorCategory

Error model. Messages never include user-supplied values.

type ErrorCategory = 'configuration' | 'validation' | 'runtime' | 'failure';

formatCurrency

function formatCurrency(value: number, currency: string, options?: Intl.NumberFormatOptions, locale?: string): string;

formatInstant

Format an exact instant in an explicit timezone. Defaults to the configured timezone (UTC unless configured, the specification) - never the host machine’s zone.

function formatInstant(value: Instant | ZonedDateTime, options?: DateOptions, timeZone?: string, locale?: string): string;

formatNumber

function formatNumber(value: number, options?: Intl.NumberFormatOptions, locale?: string): string;

formatPlainDate

Format a date-only value. Rendered in UTC so the calendar date never shifts.

function formatPlainDate(value: PlainDate, options?: DateOptions, locale?: string): string;

formatPlainDateTime

function formatPlainDateTime(value: PlainDateTime, options?: DateOptions, locale?: string): string;

formatPlainTime

function formatPlainTime(value: PlainTime, options?: DateOptions, locale?: string): string;

formatTimeZoneName

Localized timezone display name, e.g. “India Standard Time”.

function formatTimeZoneName(timeZone: string, style?: 'long' | 'short' | 'longOffset' | 'shortOffset', at?: number, locale?: string): string;

getDirection

Effective direction: explicit configuration wins over locale inference.

function getDirection(): Direction;

getFirstDayOfWeek

First day of week, ISO numbering (1 = Monday … 7 = Sunday).

function getFirstDayOfWeek(locale?: string): number;

getLocaleDirection

Script direction for a locale.

function getLocaleDirection(locale: string): Direction;

getMessage

Resolve a message. Placeholders use {name} and are replaced with the string form of params[name]. Missing keys raise a configuration error instead of silently rendering an unrelated fallback.

function getMessage(component: string, key: string, params?: Readonly<Record<string, string | number>>, locale?: string): string;

localeFallbacks

Locale fallback chain, e.g. “pt-BR” -> [“pt-BR”, “pt”, “en”].

function localeFallbacks(locale: string): string[];

registerMessages

Register translated messages for a component and locale. Components register their English defaults under “en”; applications add or override other locales.

function registerMessages(component: string, locale: string, messages: MessageCatalog): void;

MessageCatalog

type MessageCatalog = Readonly<Record<string, string>>;

describeRecurrence

Localized description of a rule, for summaries and accessible names.

function describeRecurrence(rule: RecurrenceRule, options?: DescribeRecurrenceOptions): string;

expandRecurrence

Occurrences of a recurring series starting at start (a date for all-day series, or a wall-clock time in timeZone), in ascending order, within from/to and at most limit. Throws RECURRENCE_EXPAND for mismatched bound kinds or an invalid limit.

function expandRecurrence(rule: RecurrenceRule, start: PlainDate | PlainDateTime, options?: RecurrenceExpandOptions): RecurrenceOccurrence[];

isRecurrenceRule

function isRecurrenceRule(value: unknown): value is RecurrenceRule;

parseRecurrenceRule

Parse iCalendar recurrence text: a bare rule value (FREQ=WEEKLY;BYDAY=MO), or lines (\n or \r\n) with one RRULE: and optional EXDATE:/RDATE: lines (floating local or VALUE=DATE values; TZID and UTC Z values are not supported there). UNTIL may be a date, a local time, or UTC (Z). Returns null for invalid or unsupported input.

function parseRecurrenceRule(text: string): RecurrenceRule | null;

recurrenceRule

Create a validated, frozen recurrence rule (RFC 5545 constraints included).

function recurrenceRule(init: RecurrenceRuleInit): RecurrenceRule;

recurrenceRuleToString

iCalendar text of a rule: an RRULE: line, then EXDATE and RDATE lines when present, separated by \n. Wall-clock EXDATE/RDATE values are floating local times (no TZID): they are read in the series timezone.

function recurrenceRuleToString(rule: RecurrenceRule): string;

DescribeRecurrenceOptions

interface DescribeRecurrenceOptions {
locale?: string;
start?: PlainDate | PlainDateTime;
timeZone?: string;
}

RecurrenceExpandOptions

interface RecurrenceExpandOptions {
timeZone?: string;
from?: Instant | PlainDate;
to?: Instant | PlainDate;
limit?: number;
disambiguation?: Disambiguation;
}

RecurrenceOccurrence

interface RecurrenceOccurrence {
readonly start: PlainDate | PlainDateTime;
readonly instant: Instant | null;
}

RecurrenceRule

interface RecurrenceRule {
readonly kind: 'RecurrenceRule';
readonly frequency: RecurrenceFrequency;
readonly interval: number;
readonly count: number | null;
readonly until: RecurrenceUntil | null;
readonly byDay: readonly RecurrenceWeekday[];
readonly byMonthDay: readonly number[];
readonly byMonth: readonly number[];
readonly bySetPos: readonly number[];
readonly weekStart: IsoWeekday;
readonly exclusions: readonly RecurrenceDate[];
readonly inclusions: readonly RecurrenceDate[];
}

RecurrenceRuleInit

interface RecurrenceRuleInit {
frequency: RecurrenceFrequency;
interval?: number;
count?: number | null;
until?: RecurrenceUntil | null;
byDay?: readonly RecurrenceWeekday[];
byMonthDay?: readonly number[];
byMonth?: readonly number[];
bySetPos?: readonly number[];
weekStart?: IsoWeekday;
exclusions?: readonly RecurrenceDate[];
inclusions?: readonly RecurrenceDate[];
}

RecurrenceWeekday

A BYDAY entry: every such weekday, or the nth (1..53 from the start, -1..-53 from the end).

interface RecurrenceWeekday {
readonly weekday: IsoWeekday;
readonly nth?: number;
}

IsoWeekday

ISO weekday: 1 = Monday … 7 = Sunday.

type IsoWeekday = 1 | 2 | 3 | 4 | 5 | 6 | 7;

RecurrenceDate

A date (all-day series) or wall-clock start in the series timezone (EXDATE and RDATE values).

type RecurrenceDate = PlainDate | PlainDateTime;

RecurrenceFrequency

type RecurrenceFrequency = 'daily' | 'weekly' | 'monthly' | 'yearly';

RecurrenceUntil

End of a series: a date (all-day series), a wall-clock time, or an exact instant.

type RecurrenceUntil = PlainDate | PlainDateTime | Instant;

onNodeRelease

Framework integrations: run release once when the component no longer uses node. Returns node.

function onNodeRelease<T extends Node>(node: T, release: () => void): T;

releaseNode

Components: a node returned by a render hook (or passed as content) is no longer used. Idempotent; strings, null, and unregistered nodes are ignored. A failing release callback is reported and never breaks the component.

function releaseNode(node: Node | string | null | undefined): void;

releaseNodes

Release every node in nodes (see releaseNode).

function releaseNodes(nodes: Iterable<Node | string | null | undefined>): void;

sanitizeHtml

Sanitize untrusted HTML into a DocumentFragment owned by targetDocument. Prefer this over string output: the result can be inserted with element.replaceChildren(fragment) without any HTML sink.

function sanitizeHtml(html: string, policy?: SanitizePolicy, targetDocument?: Document): DocumentFragment;

sanitizeHtmlToString

Sanitize and serialize. Output is stable: sanitizing it again yields the same string.

function sanitizeHtmlToString(html: string, policy?: SanitizePolicy): string;

setSanitizedHtml

Replace an element’s children with sanitized content.

function setSanitizedHtml(element: Element, html: string, policy?: SanitizePolicy): void;

defaultSanitizePolicy

const defaultSanitizePolicy: Readonly<{
elements: Readonly<{
p: never[];
br: never[];
hr: never[];
strong: never[];
b: never[];
em: never[];
i: never[];
u: never[];
s: never[];
sub: never[];
sup: never[];
mark: never[];
small: never[];
span: never[];
h1: never[];
h2: never[];
h3: never[];
h4: never[];
h5: never[];
h6: never[];
ul: never[];
ol: never[];
li: never[];
blockquote: string[];
pre: never[];
code: never[];
a: string[];
}>;
globalAttributes: readonly string[];
urlSchemes: readonly string[];
allowRelativeUrls: true;
maxLength: number;
}>;

SanitizePolicy

interface SanitizePolicy {
readonly elements?: Readonly<Record<string, readonly string[]>>;
readonly globalAttributes?: readonly string[];
readonly urlSchemes?: readonly string[];
readonly allowRelativeUrls?: boolean;
readonly maxLength?: number;
}