Shareable components: cross-framework reusability

Vadym Barylo
Level Up Coding
Published in
6 min readMar 24, 2023

--

Photo by David Pisnoy on Unsplash

A healthy software system is a system that always evolving. In their nature, it is sensitive to business deviations, priority changes, and vector adjustments, as well as to technology shifts that might have a positive effect on overall business metrics.

Exploring different approaches to building software faster usually resulted in compacting big monoliths into single-purpose modules and sub-systems connected together with the goal to use the most efficient setup for the current business unit.

The rise of microarchitecture is also stipulated by the variety of solutions available around the particular problem, so the cost of implementation is more cost of choosing the most appropriate instrument for this problem.

The power of existing low-code and no-code instruments only strengthens the belief that efficiency is not a measurement of the amount of code written but the fullness and comprehensiveness of integration coverage of existing solutions.

In this paradigm, starting coding to solve a business ask is considered the least acceptable solution nowadays as it is most probably the wheel reimplementation by some degree. Collecting different independent moving parts together is a more recognizable skill in modern design.

UI ecosystem is not an exclusion here. Reusing complex widgets across different applications is the basic motive for inventing and supporting narrowly specialized component libraries and finding specific business modules.

The bigger challenge emerges when the same UI modules need to be used in different applications that are based on different high-level frameworks, like Angular and React. How reusability for UI modules can be obtained in this case?

Native components

In a heterogeneous eco-system, that consists of applications written using many different frameworks, the cost of the “re-usability” architecture attribute is especially costly.

The most reasonable solution is to perform on a level that is a building block for any high-level framework — HTML primitives. This can be considered the lowest common denominator for such a type of architecture. As any high-level framework inevitably operates with HTML primitives and native browser API — we can work on the same level and encapsulate reusable code blocks into HTML custom elements.

Using custom elements to share common behaviors

This approach is the safest as doesn’t depend on host framework specifics (version, limitations, etc.).

Drawbacks of this approach:

  • support only modern browsers
  • limited coverage for UI reach component libraries
  • lowest possible development speed because we operate on the lowest API level

Solutions:

  • SolidJS — is not a real native, but very close to it and with very small performance penalty because of it. Uses React-like syntax to compile to native HTML instruction (not virtual DOM). It has already some ecosystem of high-level components around (Hope UI, SUID, Kobalte)
  • Material Web — beta version of Google Material components
  • Polymer — abstraction over native Web Components API that simplifies its creation:
class MyElement extends PolymerElement {
static get properties() { return { mood: String }}
static get template() {
return html`
<style> .mood { color: green; } </style>
Web Components are <span class="mood">[[mood]]</span>!
`;
}
}
  • Vaadin web components — the community-supported library of rich web components that already includes most of the widely used complex controls like grid, accordion, etc.
  • Elix — is also a community-driven collection of high-quality web components for common user interface patterns.
  • Patternfly elements — is a work-in-progress collection of flexible and lightweight Web Components based on the Unified Design Kit. Also includes a generator to build new components.
  • Fluent UI — supported by Microsoft library of Web Components that composes @microsoft/fast-foundation and supports Microsoft's Fluent design language.

Homogenous components

When browser nativeness is too low for complex businesses to move fast — we can consider a more interesting approach of components reuse — make them native to a specific framework from single codebase during runtime or compile time.

In other words — we develop components using specific rules to later build them into native Angular or React components and use them natively for applications but not a browser.

Also, as we already operate on a higher level than browser native API using specialized frameworks — many features like data-binding, state management, JSX format, etc. are already supported out of the box.

Using homogeneous components to share common behavior

Drawbacks of this approach:

  • if the number of frameworks to support increases — the complexity of basic common elements increases significantly
  • “framework nativeness” is also limited by the feature set we can use
  • because the main idea of this approach is to compile components into framework-compatible versions — during the design time we can’t access the features of the particular framework

Solutions:

  • Mitosis — write components in React-like language, and compile to different (React, Angular, Vue, etc) frameworks. One of the most promising in this field and actively supported by the Qwik creators.
  • ZagJS — component library to work seamlessly in different frameworks (Angular not supported).

Heterogenous components

But what if we already have a handy, well-supported, and well-tested suite of components and we want to use it as is in any next application without re-writing using low-level primitives or when compilation can’t be successful because of the specific framework used?

The last type of reusable components are those that are native to a specific framework (e.g. React), but there is a mechanism to inject them into applications of different types (e.g. Angular based).

Using heterogeneous components to share common behavior

Drawbacks of this approach:

  • there is resource size overhead as the component is bundled with the engine it is running on. So in case many components of such type — application size and start time can be very affected
  • if there is a need to support many frameworks — a matrix of compatibility becomes too big and requires significant efforts to support

Solutions:

Conclusion

Frameworks’ “popularity” is a very volatile metric. Very unlikely to expect that the company will always be locked to the particular vendor for its lifecycle and that any next home-grown solutions will follow the same recommendations and practices. Everything is changing so fast.

Accepting this we can conclude that the components’ re-usability challenge is very probably to happen to the majority of companies during their evolution.

Taking into account the fact that the Web eco-system very confidently stepping into a new era of custom Web Components, customer isolation, WebAssembly as a new runtime and many more — additional contributions in this field will have additional positive effects to migrate smoother and faster to this new technology era. So helping to evolve components that are native to modern browsers inevitably will have a positive effect on the whole industry in short term. Let’s step into the modern world.

Level Up Coding

Thanks for being a part of our community! Before you go:

🚀👉 Join the Level Up talent collective and find an amazing job

--

--