Web components
Web components started with the promise of letting developers piece them together and build great apps on top of them. Examples of such atomic components are GitHub's time-elements, Stefan Judis' web-vitals-element, or, shameless plug, Google's dark mode toggle. When it comes to complete design systems, however, I have observed that people prefer to rely on a coherent set of components from the same vendor. An incomplete list of examples includes SAP's UI5 Web Components, the Polymer Elements, Vaadin's elements, Microsoft's FAST, the Material Web Components, arguably the AMP components, and many more. Due to a number of factors out of scope for this article, a lot of developers, however, have also flocked to frameworks like React, Vue.js, Ember.js, etc. Rather than giving the developer the freedom to choose from any of these options (or, dependent on your viewpoint, forcing them to make a technology choice), super app providers universally supply a set of components that developers must use.
Components in mini apps
You can think of these components like any of the component libraries mentioned above. To get an overview of the available components, you can browse WeChat's component library, ByteDance's components, Alipay's components, Baidu's, and Quick App components.
Earlier I showed that while, for example, WeChat's <image>
is a web component under the hood, not all of these components are technically web components. Some
components, like <map> and <video>, are rendered as
OS-built-in components
that get layered over the WebView. For the developer, this implementation detail is not revealed,
they are programmed like any other component.
As always, the details vary, but the overall programming concepts are the same across all super app providers. An important concept is data binding, as shown before in Markup languages. Generally, components are grouped by function, so finding the right one for the job is easier. Below is an example from Alipay's categorization, which is similar to the component grouping of other vendors.
- View containers
viewswiperscroll-viewcover-viewcover-imagemovable-viewmovable-area
- Basic content
texticonprogressrich-text
- Form components
buttonformlabelinputtextarearadioradio-groupcheckboxcheckbox-groupswitchsliderpicker-viewpicker
- Navigation
navigator
- Media components
imagevideo
- Canvas
canvas
- Map
map
- Open components
web-viewlifestylecontact-button
- Accessibility
aria-component
Below, you can see Alipay's <image> used in an
a:for directive (see List rendering) that loops over an image data array
provided in index.js.
/* index.js */
Page({
data: {
array: [
{
mode: "scaleToFill",
text: "scaleToFill",
},
{
mode: "aspectFit",
text: "aspectFit",
},
],
src: "https://images.example.com/sample.png",
},
imageError(e) {
console.log("image", e.detail.errMsg);
},
onTap(e) {
console.log("image tap", e);
},
imageLoad(e) {
console.log("image", e);
},
});
<!-- index.axml -->
<view class="page">
<view class="page-section" a:for="{{array}}" a:for-item="item">
<view class="page-section-demo" onTap="onTap">
<image
class="image"
mode="{{item.mode}}"
onTap="onTap"
onError="imageError"
onLoad="imageLoad"
src="{{src}}"
lazy-load="true"
default-source="https://images.example.com/loading.png"
/>
</view>
</view>
</view>
Note the data binding of the item.mode to the mode attribute, the src to the src attribute,
and the three event handlers onTap, onError, and onLoad to the functions of the same name. As
shown before, the <image> tag internally gets converted into a
<div> with a placeholder of the image's final dimensions, optional lazy loading, a default source,
etc.
The available configuration options of the component are all listed in the documentation. An embedded-in-the-docs component preview with simulator makes the code immediately tangible.