Stateless
Escape Hatch - anti-pattern
Elements are intentionally as stateless as possible. This means elements do not maintain any internal state but rather only render based on the information/state passed to the element via properties/attributes. Consider the following example with a modal element.
<nve-modal></nve-modal>
With the modal, the goal is to show or hide based on some application logic. No open or show property exists. The application fully controls the logic to determine whether to show the modal.
Instead of defining an open or show state, the element provides a close event. This event fires when the user has clicked the close button within the modal. The modal itself does nothing but emit the event. The modal only notifies the application the user had clicked the close button. The application then determines what it should do.
This is important as it provides a much more flexible API and prevents "escape hatch" APIs. If the modal controls the visibility state, and the application needs to check logic before closing, yet another API would need to intercept before the close event (example: onBeforeClose). Consider how an Angular app would use a stateless example.
<nve-button (click)="showModal = true">open modal</nve-modal>
<nve-modal *ngIf="showModal" (close)="closeModal($event.detail)">
Some Content
</nve-modal>
export class AppComponent {
showModal = false;
async closeModal() {
const valid: boolean = await someAsyncValidationCheck();
if (valid) {
this.showModal = false;
} else {
warnOfPotentialIssues();
}
}
}
Because the application manages the state, the developer now has the flexibility to intercept and run extra checks before closing the modal. While this is a subtle difference when compared to the stateful version, it provides a more flexible element and keeps the public API surface small.
Synchronizing State
Stateless elements also prevent the state from becoming out of sync. If the modal retains an internal visibility state, this opens up the potential for bugs where the element is out of sync with the application state. View the demos below to learn more detail about the risks of stateful leaf elements.
Stateful Events - anti-pattern
Do not emit/reflect events in response to setting state on the element. This is unnecessary from the consumer API as the application component does not need event updates for the state it maintains. Example: when you set an expand property, do not emit an expand-change event in response. Only user interactions, not property updates, should trigger events.
Always derive internal state from incoming properties and not user actions. Example, setting a expanded property on an element can cause the element to set css classes and aria-* attributes to visually and semantically represent the expanded state.