Using Web Components Using a combination of JavaScript, HTML, and CSS standard APIs we are able to capture a UI solution in the form of a web component. This is very useful because it allows us to quickly and consistently reproduce UI solutions when the appropriate use case arises. Let's take a button for example, there are CSS rules around making a button look a certain way and it includes variations, such as background-color, that you might want to capture as options for your button. You can create a button web component that does just that, it implements all of the functionality of a button and gives the ability to add configurations to modify the rendered view. The component captures the UI solution and the intent behind it, and exposes those configuration points to anyone who uses it to deliver a combination of markup, styles, and interaction that make up a piece of the UI. Guiding Principles There are some guiding principles that are followed in this set of components that will help understand the choices made to build them. Let's quickly step through them and explain each one. Components Only Provide UI There are no fetch calls or application logic in any of our components, just logic to determine how information should be presented or drive UI behaviors. It is up to the users of the component to populate them with data and implement application logic. UI is a Result of a Component's State This is the same principle that many frameworks have adopted to ensure a predictable UI from each component. Each component reads its current state and returns a rendered result based on that. If the state changes, such as an attribute changing then the result is recalculated. User-Defined State is Stored on the DOM Our components are custom HTML elements that have their own attributes that are mapped to the class properties which behave as a proxy for them. We have a tool that helps us manage that relationship, and the big takeaway here is that the component reads its state from the DOM and if it changes its state it writes it to the DOM. There are some exceptions here, for example with rich data that cannot be stored on the DOM, but usually if a user can define it, it is stored on the DOM. Components Rely Heavily on Available CSS The design system predates the components and supplies many CSS utilities or styles written for a specific UI that our components implement. In most cases our components are simply composing these available class names to achieve the UI. What that means is that there is very little styling that the components are doing that is not available to you outside of them. The components are the implementation of the design system and help you quickly create the UIs that it supports. Components are Composable Each component has all of the required information to render the UI, and even components that are designed to be children of other components can be used in a standalone way, albeit with limited use. What this means is that components can be safely used as children of other components. For example, many of our components use the suite-text or suite-surface components as a part of their markup. Understanding SuiteElement The SuiteElement class is the base that all of our components are built on. It comes with several key features that make crafting components easier for us and some of our other tools are designed to work with it. The documentation component is designed to automatically generate documentation based on it. I'll cover each of those features in detail. Render Method Each component has a render method that calculates the state and returns the UI. Each time the state changes, the render method will be called to determine the new resulting UI and push it to the renderRoot (either the DOM or a shadow DOM). Be careful when making state changes in the render method as it could cause a loop and it is advised to handle changes through an event handler or some other means that is less direct. Component Metadata There is a static on each component constructor called "metadata" that describes the component itself. This is used by the documentation component to generate some sections of the documentation website. It contains the name of the component, mapped attributes, custom events, and user-set properties. Mapped Attributes The @mapAttribute() decorator handles creating a connection between a class property and a HTML attribute while providing some other utilities for attributes and stores details about the attribute on the metadata static. When you call this decorator on a property you are setting that property up to be a proxy for the attribute. A getter and setter will be created that interact with the attribute and handle any data conversion requested by the decorator. Define Event This is a tool for defining custom events on a component and will adds any defined events to the metadata static. This is used by the documentation component to generate a table detailing information for each custom event. Custom events are useful for passing data between elements or for creating unique behaviors for a component. Lifecycle Events SuiteElement is set up so that at different points in the lifecycle of a component it will trigger a custom event for anyone listening. This event will fire for the following points in a component's lifecycle:
"suite-connected"
Triggers when the element in the DOM invokes the JavaScript class and before any setup logic is run
"suite-disconnected"
Triggers when the element is removed from the DOM NOTE: The element is removed from the DOM before the event is invoked and this makes event delegation fail, so to listen to this event the listener MUST be on the element itself.
"suite-initialized"
Triggers when the class has finished processing the setup logic and has rendered to the screen
"suite-reflected"
Triggers whenever a mapped attribute's syncronization logic runs