Elements

LYNX_ELEMENTS declares every Lynx element as an Angular directive, so your templates type-check. import { LYNX_ELEMENTS } from '@blotch/angular-lynx';

Usage

src/app/greeting.ts
import { Component, signal } from '@angular/core';
import { LYNX_ELEMENTS } from '@blotch/angular-lynx';

@Component({
  selector: 'app-greeting',
  imports: [LYNX_ELEMENTS],
  template: `
    <view class="card">
      <image [src]="avatar()" />
      <text>Hello from Lynx</text>
    </view>
  `,
})
export class Greeting {
  readonly avatar = signal('https://example.com/avatar.png');
}
  • When it's needed: your editor's type checking and ng test need it. ng build and ng serve add CUSTOM_ELEMENTS_SCHEMA for you, so they pass without it.
  • Attributes: each directive declares its element's attributes as inputs, so [src]="url()" type-checks. Bind any other attribute with [attr.name].
  • Events aren't declared as outputs. Bind them by name, such as (bindtap). See Handling taps and events.

API

LYNX_ELEMENTS

const LYNX_ELEMENTS: readonly [
  typeof LynxView,
  typeof LynxText,
  // …every directive in the table below, in this order
];

Every directive below, as one array for a component's imports. Each directive is also exported on its own.

DirectiveSelectorReference
LynxViewview<view>
LynxTexttext<text>
LynxInlineTruncationinline-truncation<text>
LynxImageimage<image>
LynxScrollViewscroll-view<scroll-view>
LynxListlist<list>
LynxListItemlist-item<list>
LynxBlockblock<block>
LynxIfifNo page
LynxForforNo page
LynxFrameframe<frame>
LynxInputinput<input>
LynxTextareatextarea<textarea>
LynxInputValueAccessorinput with a form directiveBelow
LynxTextareaValueAccessortextarea with a form directiveBelow
LynxOverlayoverlay<overlay>
LynxRefreshrefresh<refresh>
LynxRefreshHeaderrefresh-header<refresh>
LynxScrollCoordinatorscroll-coordinator<scroll-coordinator>
LynxScrollCoordinatorHeaderscroll-coordinator-header<scroll-coordinator>
LynxScrollCoordinatorSlotscroll-coordinator-slot<scroll-coordinator>
LynxScrollCoordinatorSlotDragscroll-coordinator-slot-drag<scroll-coordinator>
LynxScrollCoordinatorToolbarscroll-coordinator-toolbar<scroll-coordinator>
LynxSvgsvg<svg>
LynxViewPagerviewpager<viewpager>
LynxViewPagerItemviewpager-item<viewpager>
LynxBlurViewblur-view<blur-view>
LynxVideovideo<video>
LynxWebViewwebview<webview>
LynxCoverViewcover-view<cover-view>
LynxTitleBarViewtitle-bar-view<title-bar-view>

LynxIf and LynxFor

@Directive({ selector: 'if' })
class LynxIf {}

@Directive({ selector: 'for' })
class LynxFor {}

Declare Lynx's own low-level <if> and <for> elements, so a template that contains them type-checks. They're unrelated to Angular's @if and @for blocks, and AngularLynx doesn't test them. Use @if and @for instead.

Attributes on every element

Every directive above, except the two form accessors, also accepts these inputs.

AttributeTypeDescription
idstringElement ID. Selector queries find elements by it.
namestringA name some Lynx APIs use to find the element.
user-interaction-enabledbooleanWhether the element receives touch events. Default true.
native-interaction-enabledbooleanWhether the element receives the platform's own gestures.
event-throughbooleanLets touches pass through to the elements below.
hit-slopstring | objectExtends the touch area beyond the element's box.
block-native-eventbooleanWhether the element consumes native iOS and Android gestures.
ignore-focusbooleanStops the element from taking focus.
ios-enable-simultaneous-touchbooleanLets iOS recognize this touch together with others.
accessibility-*, a11y-idSee Accessibility.
exposure-*See Exposure.

LYNX_FORM_ACCESSORS

const LYNX_FORM_ACCESSORS: readonly [
  typeof LynxInputValueAccessor,
  typeof LynxTextareaValueAccessor,
];

Both form value accessors as one array. LYNX_ELEMENTS already contains them.

LynxInputValueAccessor and LynxTextareaValueAccessor

@Directive({
  selector:
    'input[formControlName], input[formControl], input[ngModel], input[formField]',
})
class LynxInputValueAccessor implements ControlValueAccessor {}

@Directive({
  selector:
    'textarea[formControlName], textarea[formControl], textarea[ngModel], textarea[formField]',
})
class LynxTextareaValueAccessor implements ControlValueAccessor {}

Connect <input> and <textarea> to reactive forms, ngModel and Signal Forms' [formField]. They switch on only when one of those form directives is on the element. Angular forms calls their members; you don't. Both classes have the same members.

onInput()

onInput(event: Event): void;

Runs on bindinput. Sends the typed text, event.detail.value, to the form control.

onBlur()

onBlur(): void;

Runs on bindblur. Marks the control as touched.

writeValue()

writeValue(value: string): void;

Shows the form value in the field through the element's setValue UI method. Lynx ignores changes to the value attribute after the user has typed, so form.reset() and setValue() need this.

registerOnChange() and registerOnTouched()

registerOnChange(fn: (value: string) => void): void;
registerOnTouched(fn: () => void): void;

Store the callbacks Angular forms passes in.

setDisabledState()

setDisabledState(isDisabled: boolean): void;

Sets or removes the element's disabled attribute.

Types

None of its own. ControlValueAccessor comes from @angular/forms.