MiniApp Components are the building blocks to creating MiniApp Pages. These components encapsulate functionality, data, and styles, enabling developers to create custom and reusable items that can be combined to develop MiniApps. This specification aims to specify a set of common practices to define [=MiniApp Components=] that allow developers to build similar user interfaces across MiniApp platforms efficiently and provide a consistent user experience.

Introduction

[=MiniApp Components=] are the building blocks to creating MiniApp Pages. These components encapsulate functionality, data, and styles, enabling developers to create custom and reusable items that can be combined to develop MiniApps. MiniApps include essential elements like page containers, textual and multimedia content, and other interactive features like forms.

To align MiniApps and Web applications, MiniApps may be defined using Web resources (i.e., HTML, CSS, and scripts) as described in [[MINIAPP-PACKAGING]]. Despite this, traditionally, MiniApp implementations offer specific non-standard features and mechanisms facilitating the development and implementation of the MiniApp Components.

Although MiniApp Components share the same concept as Web Components, their capabilities and development features differ. The main differences are motivated by the architecture of the existing implementations along the MiniApp ecosystem following the MVVM pattern, based on components developed through domain-specific markup languages and without access to the standard DOM.

To avoid overlap with Web Components, also supported by MiniApp user agents, this specification aims to be an informative reference and is not intended to be a formal standard. Thus, it aims to specify a set of common practices to define [=MiniApp Components=] that allow developers to build similar user interfaces across MiniApp platforms efficiently and provide a consistent user experience.

Component Basics

MiniApp Pages and Components

A MiniApp Component is a custom MiniApp element with encapsulated functionality, data, and styles that can be reused in MiniApp Pages.

Each [=component=] is defined by three documents: an HTML resource, defining the structure and static content of the component; a style sheet with the styles and appearance configuration for rendering; and a script resource to control de business logic of the component. A component may be composed of other sub-components (stored within the package) and predefined built-in elements, similar to [=HTML Elements=].

Components and subcomponents are organized hierarchically in a tree. Although the functions and styles are encapsulated, a component may communicate with its relative nodes using events. Developers may configure the Pages of the app using the manifest document [[MINIAPP-MANIFEST]], pointing to the specific component associated with the page.

Components structure of a MiniApp (pages and components)
Structure of a MiniApp including components and subcomponents

MiniApp Interface

Formal definition of the interface?

Templating

MiniApps have an advanced one-way data binding, with a Mustache-based templating mechanism, to reduce code redundancy and maximize maintenance efficiency.

Component templates are defined in the primary HTML resource associated with the component. The templating implementations are based on DOM, with XML or HTML elements and special attributes.

Every component instance is defined as a data object with properties and methods bound to the template. The object that contains the component's data and the business logic, managed by the [=Document/logic layer=], communicates the template instance (in the [=Document/view layer=]) of the changes produced on the data properties to proceed with the view update.

Content Interpolation

Component's templates support text interpolation using the Mustache syntax through double curly braces (`{{}}`). The component's properties, defined in a scripting resource and managed by the [=Document/logic layer=], are bound to the corresponding component's template file, described in the HTML resource that runs on the [=Document/view layer=].

The templating mechanism replaces mustache tags with the value of the properties defined under the same name in the component.

<!-- my-component.html -->
<div>{{foo}}</div>

...

// my-component.js
export default {
  props: {
    foo: 'bar'
  }
}
      

In the previous example, the mustache element `{{foo}}` is replaced with the textual value of the `foo` property on the corresponding component instance. The value of this mustache variable will be updated during the execution when the `foo` property changes. The process can be summarized as follows:

  1. The system identifies the component's properties and methods associated with the mustache variables in the template instance.
  2. It monitors changes in the component's object status.
  3. Once one monitored variable changes (in the [=Document/logic layer=]), the update is communicated to the template instance (in the [=Document/view layer=]).

Component Declaration

MiniApp user agents provide a series of essential built-in components (also called native elements or native components) equivalent to the standard [=HTML Elements=]. These built-in elements allow developers to create customized components that can be instantiated and re-used by other MiniApp components.

Similarly to the standard [=HTML Elements=], developers may use the MiniApp built-in elements to create and customize components. A user-defined component requires three main resources [[MINIAPP-PACKAGING]]:

Developers use these HTML resources to define the structure and static content of the component, using the built-in elements and other custom components existing in the package.

A MiniApp component encapsulates its logic and stylesheet. So, the default style sheet and scripts only affect the elements and components defined in the HTML resource. Still developers may use other scripts and style sheets upon explicit declaration.

MiniApp user agents specify a mechanism to send data from the component's scripting resource (e.g., `my-component.js`) run in the [=Document/Logic layer=] to the components and elements in the [=Document/View layer=] during runtime execution. User agents interpret the scripting resources as ECMAScript Modules (ESM) that use the `export` declaration in the source file. This scripting resource associated with the main HTML resource is expected to have an anonymous `export default` declaration that contains the component object initializer, which includes callback functions used in events and data properties used in events accessible from the [=Document/View layer=]. They may also have other auxiliary variables, constants, and methods needed for the component's logic.

// my-component.js

export default {
  // data attributes 
  // properties
  // event listeners
  // methods 
}
    

Component Data, Properties and Methods

The scripting resources (e.g., `my-component.js`) use the `export` keyword to expose an object with the component's data, properties, and methods, making them available to the [=Document/View layer=].

Components may have data attributes. These attributes are variables that store information specific to that component and usually hold component states that can influence the logic and UI of the application. These attributes are generally defined directly as part of the component's definition.

// my-component.js

export default {
  color: 'Red',
  title: 'My component'
}
      

A property is an attribute that can be assigned to the component when it is instantiated, allowing for customization and dynamic behavior. Properties can be considered variables initialized when passed down to the component and can hold a value and be updated as needed. Properties are usually defined by the key `props`, whose value is an object of key-value properties. The key in the object determines the property's name and its value is an object that defines the data type (`type` member) and value (`value` member).

// my-component.js

export default {
  props: {
    foo: {
      type: String,
      value: 'bar'
    }
  }
}
      

The definition could avoid the data type, allowing any.

// my-component.js

export default {
  props: {
    foo: {
      value: 'bar'
    }
  }
}
      

Developers can also define the property's name without initializing it with a default value. This could be useful if the property is set up within the methods of the component. Properties could also be defined as a list of names.

// my-component.js

export default { 
  props: ['foo','button','title'],
}
      
// parent-component.html
<my-comp button="Next" title="Item #1">
      

Internal methods and callback functions of a component are also defined in the object initializer of the primary scripting resource. A property key represents the method's name, and the value includes its definition.

// my-component.js

export default {
  loadMore: function(event) {
    console.log(event);
  }
}     

Built-in Methods

Although they are similar, MiniApp components do not implement the methods and attributes of the {{HTMLElement}} interface. The decoupling of [=Document/Logic layer=] and [=Document/View layer=] causes the logic of the component instance cannot directly access the DOM of the page. MiniApp user agents solve this challenge with specific interfaces that include built-in properties and methods exposed on the component public instance (i.e., accessible through `this`) for the following purposes:

  • Access/add/modify a data property.
  • Get the root component instance of the current component tree.
  • Get the parent component instance.
  • Get a child component instance based on its identifier.
  • Support communication between relatives. Components trigger events that can be propagated to their parents, along with their associated data. The parent component gets the child's instance, accessing its data and methods.
How to register a component? Just with the manifest?

Component Reuse

A component may use other custom components registered and defined within the package. For that, developers must import the custom component in the parent component declaration. The imported component is exposed to the component template. It will be available as another tag in the template, identified by a unique key.

<!-- my-component.html -->

<import src="./cool-button" name="cool-button" />

<div>
  <cool-button></cool-button>
</div>

Like in Web Components, MiniApp components may use [^slot^] elements as placeholders to pass content from the parent to the child component.

<!-- my-component.html ->
<div class="item">  
   <slot name="title"></slot> 
</div>
Access to component nodes?

Component Events

As defined in [[UIEVENTS]], an event is the representation of an occurrence (such as a mouse click on the presentation of an element, the removal of a child node from an element, or any number of other possibilities) that is associated with its event target. Each event is an instantiation of one specific event type.

MiniApp user agents have a dual-thread architecture, decoupling the logic and rendering engines. Therefore, the logic layer does not have access to the complete DOM tree of the document in the rendering layer, and the event targets (nodes in the rendering layer) do not always support the standard DOM Events model as defined in [[DOM]]. MiniApp agents usually provide a customized event system to deal with events on the virtual DOM nodes.

Event Handlers

Elements in components can have event handlers specified. An event handler is composed of a value, usually an internal reference, and a listener, a callback function responsible for processing the algorithm for that event handler. In MiniApp components, the event handlers are exposed using event handler content attributes. These handlers are exposed through a name that starts with a specific keyword (`on`, `bind`, or others), followed by the event type identifier.

<!-- my-component.html -->
  <text onclick="loadMore">example</text> 
    <!-- or -->
  <view bindtap="loadMore">example</view>

Due to the decoupled architecture, MiniApp elements do not implement the {{EventTarget}} interface, so they do not implement the {{EventTarget/addEventListener()}} function. Therefore, event binding is only performed statically using handler content attributes on the component elements. The callback function associated with the event handler is specified in the scripting resource in scope, as a member of the exported anonymous object.

// my-component.js

  export default {
    loadMore(event) {
      console.log(event);
    }
  }
      

Likewise, developers can also define the callback functions to process the lifecycle events.

// my-component.js

  export default {
    oncreated() {
      console.log('Component created!');
    },
    onready() {
      console.log('Component is ready!');
    }
  }

Types of Events

MiniApp user agents implement support for a common set of event handlers supported by all their component elements, similar to HTML. However, MiniApps have been traditionally implemented in native environments, not focused on the Web, so the names of the types might vary. Also, MiniApps user agents usually implement different event types by default.

The following list contains the handlers event types, supported by all MiniApp component elements:

`touchstart`
Like the touchstart event type defined in [[TOUCH-EVENTS]], this event is dispatched on the topmost component (event target) indicated by the pointer when the user places a touch point on the touch surface.
`touchmove`
Like the touchmove event type defined in [[TOUCH-EVENTS]], this event is dispatched on the topmost component (event target) indicated by the pointer when the user moves a touch point along the touch surface.
`touchcancel`
Like the touchcancel event type defined in [[TOUCH-EVENTS]], this event is dispatched on the topmost component (event target) indicated by the pointer when the touch point has been disrupted in an implementation-specific manner.
`touchend`
Like the touchend event type defined in [[TOUCH-EVENTS]], this event is dispatched on the topmost component (event target) indicated by the pointer when the user removes a touch point from the touch surface, also including cases where the touch point physically leaves the touch surface.
`click` or `tap`
Like the click event type defined in [[UIEVENTS]], this event is dispatched on the topmost event target indicated by the pointer when the user presses down and releases the primary pointer button or otherwise activates the pointer in a manner that simulates such an action.
`longtap` or `longpress`
The `longpress` or `longtap` event type is dispatched on the topmost component (event target) indicated by the pointer when the user presses down, holds for a specific period, and releases the primary pointer button or otherwise activates the pointer in a manner that simulates such an action.

The minimum value of the longpress or longtap period may vary depending on the implementation (e.g., Android's default timeout is 400 ms). Some platforms may allow developers to change the value by default.

Scripting Resources

MiniApp user agents support scripting resources to define the business logic and operation of the components. Although the aim of this specification is not to recommend a specific scripting language, the document considers ECMAScript (broadly known as JavaScript) [[ECMASCRIPT]] as the scripting language by default.

As indicated in [[MINIAPP-PACKAGING]], each MiniApp component has a scripting file (with the `.js` extension). Since each component has its own scope, the functions and variables defined in the scripting file have global scope across the entire component, but they are isolated from the rest of the MiniApp components.

Scripts in components support module management. Modules have an independent scope, so the elements defined in a module are private by default and invisible to other modules. The exposition of the concrete module variables or functions MUST be explicitly made through the export declarations. Only local modules (i.e., hosted in the same package) MAY be imported.

HTML resources (with the .html extension) MAY import local scripts, such as auxiliary libraries shared by the MiniApp components. These script documents SHOULD be hosted in the `/common` directory as defined in [[MINIAPP-PACKAGING]], so they will be available to any component in the package. As in the case of scripting modules, only local scripts (i.e., hosted in the same package) will be accessible to the components. Developers MAY include any scripting resource hosted in the same package from the HTML, using the `script` element, equivalent to [^script^] in HTML, with the [^script/src^] attribute to specify the URI of the document to import. The functions and variables of the imported script will have a limited scope across the entire component.

// Static import
import utils from '../common/utils.js'

// dynamic import using require()
const utils = require('/common/utils.js')

// dynamically using import()
const utils = async import('/common/utils.js')
    
<script src="../common/utils.js"><script>

Conformance of scripting resources

The script language in MiniApp packages is not restricted to ECMAScript (JavaScript). Still, this document uses it as a reference to illustrate the features that MUST be implemented and supported by MiniApps user agents.

Custom scripting resources

Some MiniApp user agents MAY support custom scripting formats to assist developers in building user interfaces. These formats are usually subsets of ECMAScript, restricted to only variables and functions that can be directly imported as a module and used from the rendering templates. Specifications vary depending on the implementation, and they use specific file extensions to identify the resource type.

  // pages/index/foo.sjs
const message = 'hello sjs';
const format = num => num.toFixed(2);
export default {
  message,
  format
};
<!-- pages/index/index.axml -->

<import-sjs from="./foo.sjs" name="utils" />

<view>{{utils.message}}</view>
<view>{{utils.format(3.14159)}}</view>

Styling

MiniApp user agents support CSS profiles based on the standard specifications defined by the CSS Working Group Snapshot [[CSS-SNAPSHOT]]. Style sheets of MiniApp components follow the CSS recommendations for syntax, selectors, rules, media queries, fonts, and other elements described in [[CSS-SNAPSHOT]] to specify the presentation of the components.

MiniApp user agents are not expected to implement full support of CSS. Instead, they MAY define specific CSS profiles with subsets of CSS properties, selectors, colors, rules, and other CSS specifications, aiming to simplify the development process and meet all their concrete requirements.

Every MiniApp component has a style sheet (with the `.css` extension) associated by default. Developers MAY include additional style sheets to reuse common styles among the components (e.g., styles for buttons or dialogs). The shared style sheets SHOULD be hosted in the `/common` directory in the package.

Developers may use the @import rule to import style rules from other style sheets. If an @import rule refers to a valid style sheet hosted locally in the package, user agents treat the imported style sheet as if its contents were written in place of the @import rule defined in [[CSS-CASCADE-4]].

/** scoreboard.css **/
@import  "../common/buttons.css";

.checkout  {
  color: yellow; 
}

Developers MAY also use the `style` element, equivalent to the [^script^] HTML element, to include CSS declarations in the primary HTML resource of the component.

<!-- scoreboard.html -->
<style src="/common/base.css"></style>

<style>
  @import '/common/base.css';
  .impact {
    color: red;
  }
</style>

Developers MAY define inline styles on specific visual elements of the component using the `style` attribute, equivalent to the [^html-global/style^] HTML common attribute.

<!-- scoreboard.html -->
  <div style="background-color:yellow;">
    This is a div
  <>

Component Lifecycle

The lifecycle of a component refers to the process from its creation to its destruction. Every MiniApp component implements a collection of lifecycle callbacks triggered at the different stages of the component lifespan. As described in [[MINIAPP-LIFECYCLE]], MiniApp pages and components are rendered on the [=Document/View layer=], while the events involving the lifecycle management are processed on the [=Document/Logic layer=] of the user agent.

The component lifecycle callbacks are `created`, `attached`, `ready`, `detached`, `show`, and `hide`. The corresponding values are either a Web IDL {{Function}} callback function type value or `null`. By default, the value of each entry is `null`.

`created`
Callback function that indicates when a component is created in the system. This callback is triggered when a custom component is first created but not necessarily attached to the page. This callback, triggered only once, is usually used to initialize the component's properties.
`attached`
This callback is triggered when the component, already created, is attached to the document tree of a page. It is usually used for initializing the data for display, such as loading images and starting animations.
`ready`
Once a custom component is attached to the page document tree, the user agent renders the component in the [=Document/View layer=], performing the calculations and adjustment of the size and the position of the component layout and its contents. This callback is triggered after the layout calculation is complete and ready to be rendered.
`detached`
This callback is triggered when the node of a custom component is removed from the page document tree. It is usually used to stop animations or halt asynchronous executions.
`show`
This callback is triggered once the user agent renders the component to the user.
`hide`
This callback is triggered when the component is hidden from the user.

There are some differences between HTML Custom Elements and MiniApp component lifecycles:

Accessibility Considerations

Security Considerations

Privacy Considerations

MiniApp Elements

Although using standard HTML elements is recommended, some MiniApp user agents implement HTML-based domain-specific languages that do not follow the standards. Most elements have standard semantic equivalences or can be implemented using standards.

Feature W3C Rec. QuickApp (Xiaomi, Huawei) Alipay Mini Program Baidu Smart Mini Program
Block container <div> <div>
<view> <view>, <scroll-view>, <movable-view>, <movable-area>
<view> <view>, <scroll-view>, <movable-view>, <movable-area>
Inline container <span> <span>
Stacking container <stack>
<cover-view> <cover-view>, <cover-image>
<cover-view> <cover-view>, <cover-image>
Slideshow (carousel) <swiper> <swiper>
<swiper> <swiper>, <swiper-item>
Tabs OpenUI's Tabs
<tabs> <tabs>, <tab-bar>, <tab-content>
<tabs> <tabs>, <tab-content>
<tabs> <tabs>, <tab-item>
Pull to refresh <refresh>
Icon image OpenUI's icon <icon> <icon>
Progress <progress> <progress> <progress> <progress>
Link (anchor) <a> <a> <navigator> <navigator>
Textual content (<cite>, <address>...) <text>
<text> <text>, <rich-text>
<text> <text>, <rich-text>
Textual input <input> <input> <input> <input>
Image capture input
<input> <input type="file" accept="image/*" capture>
<camera> <camera>
Multiple-line input <textarea> <textarea> <textarea> <textarea>
Checkbox
<input type="checkbox"> <input type="checkbox">, OpenUI's <checkbox>
<input type="checkbox">
<checkbox> <checkbox>, <checkbox-group>
<checkbox> <checkbox>, <checkbox-group>
Radio button <input type="radio"> <input type="radio">
<radio> <radio>, <radio-group>
<radio> <radio>, <radio-group>
Form <form> <form> <form>
Button <button> <input type="button"> <button> <button>
Label <label> <label> <label> <label>
Select list
<select> <select>, <option>, OpenUI's select
<select> <select>, <option>
<picker> <picker>, <picker-view>
<picker> <picker>, <picker-view>, <picker-view-column>
Slider <input> <slider> <slider> <slider>
Switch button OpenUI's switch <switch> <switch> <switch>
Picker OpenUI's select <picker>
<picker> <picker>, <picker-view>
<picker> <picker>, <picker-view>, <picker-view-column>
Image <img> <image> <image> <image>
Audio content <audio> <audio>
Video content <video> <video> <video> <video>
Canvas <canvas> <canvas> <canvas> <canvas>
animation <lottie> <lottie>
<animation-video> <animation-video>, <animation-view>
Web-view <html> <web> <web-view> <web-view>
Map
<map> <map>, <custommarker>
<map> <map>
Containers list
<list> <list>, <list-item>
Pop-up dialog <dialog> <popup>
RTC-room
<rtc-room> <rtc-room>, <rtc-room-item>
Advertisement <ad>
Payment panel <inline-payment-panel>
Comment list
<comment-list> <comment-list>, <comment-detail>
Like button <like>
Rating panel <rating>
3D-model <model> (WIP) <modelviewer>
marquee <marquee> (deprecated) <marquee>
Sharing button <share-button>
Conditional block (media query) <match-media>
Page metadata <meta> <page-meta>

Acknowledgments

List all the contributors and W3C Team contacts