Module: ojvcomponent

Oracle® JavaScript Extension Toolkit (JET)
11.1.0

F37999-01

QuickNav

JET Modules

See JET Module Loading for an overview of module usage within JET.

Description

The VComponent API is a mechanism for creating virtual DOM-based Web Components. VComponents are authored in TypeScript as Preact class-based components, with the custom element tag name specified via the @customElement decorator:

import { h, Component, ComponentChild } from 'preact';
import { customElement, GlobalProps } from 'ojs/ojvcomponent';

@customElement('oj-hello-world')
export class HelloWorld extends Component<GlobalProps> {
  render(): ComponentChild {
    return <div>Hello, World!</div>;
  }
}

In order to prepare the component for use, the VComponent must be run through the ojet CLI build process. Running ojet build will do the following:

  • Inject necessary information into the module to enable Web Component usage.
  • Generate a type definition that includes Web Component type info.
  • Generate a component.json metadata file for enabling integration with Oracle Visual Builder

Once the VComponent has been built, it can either be consumed as a plain old Web Component in HTML content, for example:

<!-- This is HTML: -->
<oj-hello-world></oj-hello-world>

Or via the Preact component class in JSX:

// This is JSX:
const hw =  <HelloWorld />

These both produce the same DOM content. That is, in both cases, an <oj-hello-world> custom element is created and added to the DOM. In the case where the VComponent is referenced via its Preact component class, this custom element is automatically created and wrapped around the rendered content (the <div> in the above example) by the VComponent framework.

Creating VComponents

VComponents can be created either by hand or via the ojet CLI's "create component" command, for example:

$ ojet create component oj-hello-world --vcomponent

When running the ojet create component commmand, the custom element tag name is specified as an argument, and the --vcomponent flag indicates that a VComponent (as opposed to a Composite Component) should be created.

(Note: if the application was originally created using the --vdom flag, the ojet create component command will default to creating VComponents and the --vcomponent flag can be omitted.

The ojet create component command creates some supporting artifacts, including:

  • A loader module
  • A style sheet and SASS files for theming
  • A resource module for translated strings

In addition, ojet will ensure that the path to the VComponent is properly configured in the application's tsconfig.json

Properties

VComponents/Preact components declare their supported properties via a type parameter. For example, as we saw above:

export class HelloWorld extends Component<GlobalProps> {

With this declaration, the component indicates that it supports the properties specified via the GlobalProps type. This type includes a subset of the global HTML attributes which represent the minimally required set of properties that all VComponents must support.

VComponents can, of course, expose other non-global, component-specific properties as well. This is typically done by declaring a type alias:

type Props = {
  greeting?: string;
  name?: string;
}

And associating this type with the first type parameter in the Component class declaration.

Since VComponents are minimally required to support the global HTML attributes defined by GlobalProps, the component-specific props must be combined with GlobalProps. The VComponent API includes a utility type to help with this: ExtendGlobalProps. Using ExtendGlobalProps, a component with the above Props type (including some default values) ends up looking like:

import { h, Component, ComponentChild } from 'preact';
import { customElement, ExtendGlobalProps } from 'ojs/ojvcomponent';

type Props = {
  greeting?: string;
  name?: string;
}

@customElement('oj-hello-world-with-props')
export class HelloWorld extends Component<ExtendGlobalProps<Props>> {
  render(props: Readonly<Props>): ComponentChild {
    const { greeting, name } = props;

    return <div>{ greeting }, { name }!</div>;
  }

  static defaultProps: Props = {
    greeting: "Hello",
    name: "World"
  };
}

In Preact, properties can be accessed either through this.props or via the first argument of the render method.

Properties can be set on the component in various ways, including:

  1. As attributes in HTML markup
  2. As properties in JSX
  3. As properties on the DOM element

One note on naming conventions: when referencing properties within JSX or on a DOM element (#2 and #3), the property name as specified in the component type is always used.

However, for attributes in HTML markup (#1), JET uses a different naming convention for multi-word attributes. As discussed in Property-to-Attribute Mapping, JET converts camelCased property names into hyphen-separated, kebab-case attribute names. As such, given the following property:

type Props = {
    preferredGreeting?: string;
}

The attribute name "preferred-greeting" is used in HTML markup:

<!-- This is HTML -->
<oj-hello-world preferred-greeting="Hi"></oj-hello-world>

And the unmodified property name is used everywhere else:

// This is JSX
function Parent() {
  return <HelloWorld preferredGreeting="Hi" />
}

// This is also JSX
function ParentOfCustomElement() {
  return <oj-hello-world preferredGreeting="Hi" />
}

// This is plain old DOM
const helloWorld = document.createElement("oj-hello-world");
helloWorld.preferredGreeting = "Hi";

Children and Slots

Many Web Components allow children to be specified, either as direct children or via named slots. A VComponent indicates that it takes arbitrary (non-named) children by declaring a "children" property using Preact's ComponentChildren type. Named slots are declared in a similar fashion, using the VComponent-specific Slot type:

import { h, Component, ComponentChildren } from 'preact';
import { customElement, ExtendGlobalProps, Slot } from 'ojs/ojvcomponent';

type Props = {
  // This indicates that the VComponent accepts arbitrary
  // (non-slot) children:
  children?: ComponentChildren;

  // And this indicates that the VComponent accepts a
  // slot named "start"
  start?: Slot;
}

Both children and slots can be embedded directly in a virtual DOM tree:

  render(props: Readonly<Props>): ComponentChild {
    return (
      <div>
        // Place the start slot before our greeting
        { props.start }

        Hello, World!

        <div>
          // And dump any other children in a wrapper div
          { props.children }
        </div>
      </div>
    );
  }

In cases where the VComponent needs to inspect children or slot content, these values must first be normalized to a flattened array by calling Preact's toChildArray.

When consuming the VComponent as a custom element, slots are specified using the slot attribute:

      <!-- This is HTML -->
      <oj-hello-world-with-children>
        <!-- This is the start slot content: -->
        <oj-avatar slot="start" initials="HW"></oj-avatar>

        <!-- This is other child content: -->
        <span>Child content</span>
      </oj-hello-world-with-children>

However, when referencing the VComponent as a Preact component, slots are configured as plain old component properties:

function Parent() {
  return (
    <HelloWorldWithChildren start={ <oj-avatar initials="OJ" /> }>
      <span>Child content</span>
    </HelloWorldWithChildren>
  )
}

Template Slots

As with other JET components, VComponents can expose template slots. Template slots differ from plain old slots in that they are invoked with some context. Template slots are most commonly used within iterating "collection" components, which need to stamp out some bit of content corresponding to each value/row/item in a data set.

Like other slots, template slots are declared as properties. Rather than using the Slot type, the TemplateSlot type is used:

import { h, Component } from "preact";
import { customElement, ExtendGlobalProps, TemplateSlot } from "ojs/ojvcomponent";

type Props = {
  // This indicates that the VComponent exposes a template
  // slot named "itemTemplate":
  itemTemplate?: TemplateSlot<ItemContext>;
}

// This is the type for the context that we'll
// pass into the itemTemplate slot
type ItemContext = {
  index?: number;
  label?: string;
  value?: string;
}

TemplateSlot is a function type that takes a single parameter: the context that is passed in when the template slot is rendered. The VComponent invokes the template slot function with this context and embeds the results in the virtual DOM tree:

// Invoke the template slot and embed the results
// in a list item:
<li> {
  props.itemTemplate?.({
    index: currentIndex,
    label: currentLabel,
    value: currentValue
  })
}
</li>

Actions and Events

As with other types of Web Components, VComponents can be the source of events, typically fired in response to some user interaction. VComponents specify their event contracts by declaring properties of the form "on<PascalCaseEventName>" of type Action. For example, the following declaration indicates that the component fires a "greetingComplete" event:

import { customElement, ExtendGlobalProps, Action } from 'ojs/ojvcomponent';

type Props = {
  onGreetingComplete?: Action;

  // Other component props...
}

Action is a function type that optionally takes an argument representing the event detail payload. For events that include a detail payload, the detail type is specified via a type parameter:

type Detail = {
  status: "success" | "failure";
}

type Props = {
  onGreetingComplete?: Action<Detail>;
}

The VComponent triggers the event by invoking the Action property and providing the detail payload:

  this.props.onGreetingComplete?.({ status: "success"});

When used in custom element form, this dispatches an actual DOM CustomEvent. See the Events and Listeners topic for details on how to respond to these events.

By default, events that are dispatched by the VComponent framework do not bubble. See the Bubbles type for info on how to declare bubbling events.

When consumed as a Preact component, no DOM events are created or dispatched. Instead, the Action callback is simply invoked directly. There is no automatic event bubbling-like behavior in this case.

The VComponent API also supports a contract for actions/events that can be vetoed by the consumer. See the CancelableAction type for details.

Methods

Some Web Components need to expose non-standard, component specific methods on their custom elements. For example, the <oj-popup> custom element exposes open, isOpen and close methods.

While it is preferable to favor declarative, property-driven APIs over imperative, method-centric contracts, the VComponent API does allow components to expose methods on their custom elements.

By default, no methods defined on the VComponent's class are surfaced on the custom element. To indicate that a VComponent method should be included in the custom element's API, simply mark the method with the @method decorator.

Writeback Properties

JET-based Web Components support a mechanism by which components can trigger changes to their own properties. For example, the JET input and select components notify consumers of changes to the value property as the user enters new values. When combined with two-way binding, this can be used to update values referenced via JET binding expressions. This process is known as "writeback". See the Writeback section in the JET Web Components topic for background.

VComponents declare writeback properties by pairing a normal property declaration with a companion callback property that is invoked when the component wants to trigger a writeback. For example, this plain old (non-writeback) value property:

type Props = {

  // This is a plain old (non-writeback) value property:
  value?: string;
}

Can be converted into a writeback by adding a second property named "onValueChanged":

import { customElement, ExtendGlobalProps, PropertyChanged } from "ojs/ojvcomponent";

type Props = {
  value?: string;

  // The presence of this callback promotes "value" into a
  // writeback property
  onValueChanged?: PropertyChanged<string>;
}

Both the event name and type are significant. In order to be recognizable as a writeback property, the companion callback property must follow the naming convention "on<PropertyName>Changed" and must be of type PropertyChanged.

Similar to Actions, invoking a PropertyChanged callback has different implications depending on whether the VComponent is being consumed as a custom element or as a Preact component.

When the VComponent is used in its custom element form, invoking the PropertyChanged callback results in an actual DOM propertyChanged event being created and dispatched. This allows JET's two-way binding mechanism to kick in. If the property is configured with a two-way binding, the new value will be written back into the expression.

In addition, when used as a custom element, triggering a writeback automatically queues a render of the VComponent, allowing the VComponent to re-render with the new value.

When the VComponent is used via its Preact component class, no DOM event is created or dispatched. Instead, the PropertyChanged callback is simply invoked with the new value. The parent component is then responsible for deciding whether re-render with the new value or not.

The VComponent API also supports writeback properties which can be read/observed by the consumer, but are only ever written by the component itself. These are known as read-only writeback properties. See the ElementReadOnly type for info on how to configure these properties.

Observed Global Properties

As discussed above, all VComponents minimally support the set of global HTML attributes defined by the GlobalProps/ExtendGlobalProps types. This means that when consuming a VComponent either via its custom element tag or VComponent class, global attributes (e.g., id, tabIndex, title, etc...) can be specified:

function Parent() {
  // We can pass GlobalProps like id into any VComponent:
  return <HelloWorld id="hw" />
}

The VComponent framework automatically transfers any global properties through to the underlying custom element in the DOM.

In some cases, the VComponent implementation may need to inspect the values of these global properties. In addition, VComponents may need to respond by re-rendering themselves when a global property is modified on the custom element. In such cases, VComponents can express interest in specific global properties via the ObservedGlobalProps utility type. This type allows specific global properties to be selected for observation via a type parameter. This type is combined with the component's other properties as part of the property declaration.

The following property declaration indicates that the component exposes "greeting" and "name" properties and also observes the global "id" and "tabIndex" props:

import { customElement, ExtendGlobalProps, ObservedGlobalProps } from 'ojs/ojvcomponent';

type Props = {
  greeting?: string;
  name?: string;
} & ObservedGlobalProps<'id' | 'tabIndex'>

Any props that are specified via ObservedGlobalProps are automatically included in the custom element's observed attributes set. As a result, any mutations to the one of these attributes on the custom element will automatically trigger a re-render of the VComponent with the new values.

Root Element

In all of the VComponents that we have seen so far, the root custom element is not included in the rendered output. Instead, this element is implicitly injected into the DOM by the VComonent framework.

In some rare cases, it may be necessary to have more control over how the the root element is rendered.

For example, consider this case of a VComponent that renders a link:

import { customElement, ExtendGlobalProps, ObservedGlobalProps } from "ojs/ojvcomponent";
import { h, Component, ComponentChild } from "preact";

type Props = {
  href?: string;
} & ObservedGlobalProps<'tabIndex'>;

@customElement("oj-demo-link")
export class OjDemoLink extends Component<ExtendGlobalProps<Props>> {

  render(props: Props): ComponentChild {
    return <a href={ props.href } tabIndex={ props.tabIndex }>Hello, World</a>;
  }
}

The intent is that the value of the global tabIndex attribute will be transferred from the root element down to the link.

However, since the tabIndex value will be automatically rendered on the root custom element, we end up with the tabIndex on two elements: on the root <oj-demo-link> and on the <a>.

To address this, we can update the render method to render both the link *and* the root custom element. The VComponent API includes a simple component that acts as a placeholder for the root element, named "Root". The Root component is exported from the "ojs/ojvcomponent" module, so we add this in our import list:

import { customElement, ExtendGlobalProps, ObservedGlobalProps, Root } from "ojs/ojvcomponent";

And then we can include the Root component in the virtual DOM tree, adjusting exactly which properties are rendered:

  render(props: Props): ComponentChild {
    return (
      // Suppress the tabIndex on the root custom element since
      // we are transferring this to the link
      <Root tabIndex={ -1 }>

        // Render the tabIndex here:
        <a href={ props.href } tabIndex={ props.tabIndex }>Hello, World</a>
      </Root>
    );
  }

The presence of the Root component impacts how global properties are managed. When the Root component is omitted, all global properties, both observed and non-observed, are automatically passed through to the root custom element. When the Root component is included at the root of the rendered virtual DOM tree, non-observed global properties are still passed through to the root custom element. However only those observed global properties that are explicitly rendered on the Root component will be passed through.

Functions

getUniqueId : {string}

For the most part, VComponents should not need to render ids on child content. However, in some cases this may be necessary. For example, in order to set up a relationship between a label and the element that the label references, the label and labeled content must rendezvous on a common id. Specifying fixed ids is problematic as this can lead to conflicts with other ids on the page. The getUniqueId() method helps solve this problem by creating producing an id that is guaranteed not to conflict with ids rendered by other components.

The id returned by getUniqueId() is typically used to provide a prefix (or suffix) for what would otherwise be a static id for some element rendered by the VComponent.

The usage model is:

  1. In the VComponent's constructor, check to see whether the VComponent already has a props.id value. If so, this can be used as a prefix for other ids and calling getUniqueId() is unnecessary.
  2. Otherwise, call getUniqueId() to retrieve the unique prefix for this component
  3. Store the result of the #1/#2 in an instance variable for later use.
  4. When rendering, use the previously stored prefix to generate unique ids for any elements that need them.
  5. Don't forget to include "id" in the list of ObservedGlobalProps in order to ensure that the VComponent receives the value of this global HTML attribute.

Putting this all together, we end up with a component like this:

import { h, Component, ComponentChild } from 'preact';
import { customElement, ExtendGlobalProps, ObservedGlobalProps, getUniqueId } from 'ojs/ojvcomponent';
import "ojs/ojinputtext";
import "ojs/ojlabel";

export type Props = ObservedGlobalProps<'id'>;

@customElement('oj-demo-unique-id')
export class DemoUniqueId extends Component<ExtendGlobalProps<Props>> {

  private uniquePrefix: string;

  constructor(props: Readonly<Props>) {
    super(props)

    this.uniquePrefix = props.id ?? getUniqueId();
  }

  render(): ComponentChild {

    const inputTextId = `${this.uniquePrefix}_input`;

    return (
      <div>
        <oj-label for={ inputTextId }>Label</oj-label>
        <oj-input-text id={ inputTextId } value="Value"/>
      </div>
    );
  }
}
Returns:
Type
string

Root

Root is a Preact component that can be used to wrap the VComponent's child content. This component should only be used for cases where the VComponent needs to control how observed global properties are rendered on the component's root custom element. In all other cases the non-wrapped child content should be returned directly.

See the Root Element section for more details.

Decorators

customElement(tagName)

Class decorator for VComponent custom elements. Takes the tag name of the custom element.
Parameters:
Name Type Description
tagName string The custom element tag name

method

Method decorator for VComponent methods that should be exposed on the custom element. Non decorated VComponent methods will not be made available on the custom element.

Type Definitions

Action<Detail extends object = {}>

The Action type is used to identify properties as action callbacks. Actions are functions that the VComponent invokes when it wants to communicate some activity to the outside world. When the VComponent is being consumed as a custom element, this results in an actual DOM CustomEvent being dispatched. Alternatively, when the VComponent is referenced via its Preact Component class, the provided callback is invoked directly and no CustomEvent is produced.

Actions have an optional detail type. If specified, the detail value is either passed to the consumer via the CustomEvent detail payload for the custom element case, or directly into the callback for the Preact component case.

Note that Action properties must adhere to a specific naming convention: "on<PascalCaseEventName>". For the custom element case, the type of the CustomEvent will be derived by converting the first character of the event name to lower case. Thus, the "onGreetingComplete" property will generate a CustomEvent of type "greetingComplete".

See Actions and Events for more info.

Signature:

(detail?: Detail) => void

Bubbles

As discussed in Actions and Events, the custom events generated by Actions do not bubble by default. The Bubbles marker type can be combined with the Action type to indicate that the Action's custom events should bubble.

type Props = {
  // This action generates bubbling custom events
  onThisActionBubbles?: Action & Bubbles;

  // This action generates non-bubbling custom events
  onThisActionDoesNotBubble?: Action;
}

CancelableAction<Detail extends object = {}>

Some JET Web Components support an asynchronous, event-based cancelation contract where prior to performing some operation, the component dispatches a "cancelable" event. If the application cancels the event, the operation is not performed. The <oj-file-picker>'s ojBeforeSelect event is one example of such an API.

The VComponent API has built-in support for this pattern via the CancelableAction type. Like the plain old Action type, CancelableAction is a function type that is used for defining callback-centric properties. One key difference between these types is that CancelableAction returns a Promise. If the Promise resolves successfully, the action is considered to be accepted. If the Promise is rejected, the action is canceled.

As with Action-typed properties, CancelableActions exhibit different behavior depending on whether the VComponent is being consumed as a custom element or via its Preact Component class.

When consumed as a custom element, invoking a CancelableAction results in a CustomEvent being created and dispatched. The detail payload of this custom event is augmented with one extra field: an "accept" method. The accept method takes a single argument: the Promise that produces the cancelation result.

When consumed via the Preact Component class, no custom event is dispatched. Instead, the callback returns the cancelation promise directly.

Signature:

(detail?: Detail) => Promise<void>

DynamicSlots

In most cases when a Web Component accepts slot content, the number and names of the slots are known, as these are defined by the component's public API. However, in some cases components may allow an arbitrary number of slots to be specified, where the slot names are not known up front. The <oj-switcher> component is an example of a component that accepts a dynamically defined (rather than predefined) set of slots.

The VComponent API supports such cases via the DynamicSlots and DynamicTemplateSlots types. A single property can be marked with the DynamicSlots type:

type Props = {

  // This property will be populated with all
  // "unknown" slots.
  items?: DynamicSlots;

  // Other properties go here...
}

When the VComponent is consumed in custom element form, this property will be populated with entries for each "dynamic" slot. That is, an entry will be added for each child element with a slot attribute that does not correspond to a known Slot-typed property. The property acts as a map from slot name to Slot instance. The VComponent can use whatever heuristic it prefers to decide which (if any) slots should be included in the rendered output.

Signature:

Record<string, VComponent.Slot>

DynamicTemplateSlots<Data>

The DynamicTemplateSlots type is a companion to DynamicSlots that is used in cases where the component accepts an arbitrary number of template slots. VComponents may declare a single property of type DynamicTemplateSlots. When the component is used as a custom element, this property will be populated with one entry for each "dynamic" template slot, where the key is the slot name and the value is a TemplateSlot function.

Note that each VComponent class can only contain a single dynamic slot property. That is, each VComponent can have one property of type DynamicSlots or one property of type DynamicTemplateSlots, but not both.

Signature:

Record<string, VComponent.TemplateSlot<Data>>

ElementReadOnly<T>

By default, writeback property mutations can be driven either by the component, typically in response to some user interaction, or by the consumer of the component. In some cases, writeback properties are exclusively mutated by the component itself. Writeback properties that cannot be mutated by the consumer are known as read-only writeback properties. The <oj-input-text>'s rawValue property is an example of such a property.

Read-only writeback properties are declared in a similar manner to plain old writeback properties, with one important difference: the ElementReadOnly utility type is used as a marker to identify the that the property is read-only.

Declarations for both forms of writeback properties can be seen below:

type Props = {

  // This is a normal writeback property:
  value?: string;
  onValueChanged?: PropertyChanged<string>

  // This is a read-only writeback property:
  rawValue?: ElementReadOnly<string>;
  onRawValueChanged?: PropertyChanged<string>
}
Signature:

T

ExtendGlobalProps<Props>

As discussed in the Properties section, all VComponents must minimally include the GlobalProps in their property types. ExtendGlobalProps is a convenience type for combining component-specific properties with GlobalProps, e.g.:

import { customElement, ExtendGlobalProps } from 'ojs/ojvcomponent';

// These are the component-specific props:
type Props = {
  greeting?: string;
  name?: string;
}

// Below we merge the component props with the
// global props using ExtendGlobalProps
@customElement('oj-hello-world-with-props')
export class HelloWorld extends Component<ExtendGlobalProps<Props>> {
Signature:

Readonly<Props> & ojvcomponent.GlobalProps

GlobalProps

The GlobalProps type defines the set of global properties that are supported by all VComponents. This includes three categories of properties:

  1. Global HTML attributes
  2. ARIA attributes
  3. Global event listeners

The following properties are included from category 1:

  • accessKey
  • autocapitalize
  • autofocus
  • class
  • contentEditable
  • dir
  • draggable
  • enterKeyHint
  • hidden
  • id
  • inputMode
  • lang
  • role
  • slot
  • spellcheck
  • style
  • tabIndex
  • title
  • translate

The following ARIA-specific attributes are included from category 2:

  • aria-activedescendant
  • aria-atomic
  • aria-autocomplete
  • aria-busy
  • aria-checked
  • aria-colcount
  • aria-colindex
  • aria-colspan
  • aria-controls
  • aria-current
  • aria-describedby
  • aria-details
  • aria-disabled
  • aria-errormessage
  • aria-expanded
  • aria-flowto
  • aria-haspopup
  • aria-hidden
  • aria-invalid
  • aria-keyshortcuts
  • aria-label
  • aria-labelledby
  • aria-level
  • aria-live
  • aria-modal
  • aria-multiline
  • aria-multiselectable
  • aria-orientation
  • aria-owns
  • aria-placeholder
  • aria-posinset
  • aria-pressed
  • aria-readonly
  • aria-relevant
  • aria-required
  • aria-roledescription
  • aria-rowcount
  • aria-rowindex
  • aria-rowspan
  • aria-selected
  • aria-setsize
  • aria-sort
  • aria-valuemax
  • aria-valuemin
  • aria-valuenow
  • aria-valuetext

The following event listener properties are included from category 3:

  • onBlur
  • onClick
  • onContextMenu
  • onDblClick
  • onDrag
  • onDragEnd
  • onDragEnter
  • onDragExit
  • onDragLeave
  • onDragOver
  • onDragStart
  • onDrop
  • onFocus
  • onKeyDown
  • onKeyPress
  • onKeyUp
  • onMouseDown
  • onMouseEnter
  • onMouseLeave
  • onMouseMove
  • onMouseOut
  • onMouseOver
  • onMouseUp
  • onPointerOver
  • onPointerEnter
  • onPointerDown
  • onPointerMove
  • onPointerUp
  • onPointerCancel
  • onPointerOut
  • onPointerLeave
  • onTouchCancel
  • onTouchEnd
  • onTouchMove
  • onTouchStart
  • onWheel

The above event listener properties can also be specified with the "Capture" suffix (e.g., "onClickCapture") to indicate that the listener should be registered as a capture listener.

Finally, onfocusin and onfocusout properties are also available, though technically speaking these are not global events.

ObservedGlobalProps

The ObservedGlobalProps type is used to identify the subset of GlobalProps that the VComponent implementation needs to observe. When a VComponent is used as a custom element, ObservedGlobalProps determines which of the GlobalProps values will be extracted from the DOM and passed into the VComponent. Properties that are selected using ObservedGlobalProps are also included in the custom element's observedAttributes list. As a result, updates to observed global properties will trigger the VComponent to render with the new values.

The ObservedGlobalProps type acts as a Pick type, where properties are implicitly picked from GlobalProps. The resulting type is typically merged with any component-specific properties via a union.

See the Observed Global Properties section for more details.

PropertyChanged<T>

The PropertyChanged type is used to identify callback properties that notify VComponent consumers of writeback property mutations. Writeback property callbacks must adhere to the naming convention of "onChanged", where "PropertyName" is the name of the writeback property with the first character converted to upper case:

type Props = {
  // This is a writeback property
  value?: string;

  // This is the corresponding property changed callback
  onValueChanged?: PropertyChanged
}

See the Writeback Properties section for more details.

Signature:

(value: T) => void

Slot

The Slot type identifies properties as representing named slot children. This type is an alias for Preact's ComponentChildren type. As such, the value of a slot property can either be embedded directly in a virtual DOM tree or can be passed to Preact's toChildArray.

See Children and Slots for more details.

Signature:

ComponentChildren

TemplateSlot<Data extends object>

The TemplateSlot type identifies properties as representing named template slot children. Unlike the Slot type, TemplateSlot is a functional type that takes some context and returns the slot children.

See the Template Slots section for more details.

Signature:

(data: Data) => VComponent.Slot