Choosing Between Inheritance vs Composition for Web Components

Different ways to Compose UI Components in Web

Piumi Liyana Gunawardhana
Bits and Pieces

--

Code reusability is one of the most commonly used best practices in modern web applications since they consist of multiple web components. However, many developers struggle to maintain a cleaner code structure with minimum redundancy while prioritizing code reusability.

So, in this article, I will discuss how we can use inheritance and composition to build reusable and clean web components.

Inheritance in Web Components

Inheritance is well-known and frequently used in Object Oriented Programming. It is referred to as inheritance when one class inherits another class’s properties to duplicate behavior and add more features.

Inheritance can be helpful in a variety of instances when developing web components. It is a method of achieving code reusability when several objects have the same properties you can reuse across the application. The ability to couple the parent-child component and reuse properties is made possible through inheritance.

For example, assume that we have a React component called SuccessButton created by extending a Button component and adding the properties like background: yellow and color: white. Likewise, you can extend the Button to have other properties such as color: red, as an ErrorButton.

The SuccessButton instance is a Button and it inherits the behavior of a Button instance. The styling variation can be attached as the className to be rendered.

class Button extends React.Component{
constructor(props){
super(props);
this.className='plain-button';
}

render(){
return {
<span className={this.className}>
{this.props.children}
</span>
}
}
}

class SuccessButton extends Button{
constructor(props){
super(props);
this.className = this.className + ' success-button';
}
}

class ErrorButton extends Button{
constructor(props){
super(props);
this.className = this.className + ' error-button';
}
}

class Main extends React.Component{
render(){
<>
...
<Button> Plain Button </Button>
<hr/>
<SuccessButton> Success Button </SuccessButton>
<hr/>
<ErrorButton> Error Button </ErrorButton>
...
</>
}
}

Composition in Web Components

Composition is also a popular concept in Object-Oriented Programming. It represents a class that can reference one or more objects of another class as instances rather than inheriting properties from a base class.

We can combine one or more components using the concept of composition to create a new, better component with enhanced behavior. Composition doesn’t try to extend an existing class or object; it just seeks to provide new behavior.

If we implement the SuccessButton and the ErrorButton with the use of composition. A SuccessButton is a component that uses the Button. But it is not a Button itself. Only the behavior of Button is passed along; properties are not inherited.

class Button extends React.Component{
render(){
return <span className={this.props.className + ' plain-button'}>
{this.props.children}
</span>
}
}

class SuccessButton extends React.Component{
render(){
return <Button className='success-button'>{this.props.children}</Button>;
}
}

class ErrorButton extends React.Component{
render(){
return <Button className='error-button'>{this.props.children}</Button>;
}
}

class Main extends React.Component{
render(){
<>
....
<Button> Plain Button </Button>
<hr/>
<SuccessButton> Success Button </SuccessButton>
<hr/>
<ErrorButton> Error Button </ErrorButton>
...
</>
}
}

When to Choose What

Choosing between inheritance and composition can be a challenging task in many scenarios. This is mainly because inheritance and composition primarily differ in how objects are related.

  • Inheritance: “is a.” E.g., The dog is an animal.
  • Composition: “has a.” E.g., The dog has four legs.

In inheritance, components are tightly coupled. For example, a parent component change can cause unintended consequences for its descendant components or the entire codebase. On the other hand, the coupling is much looser in composition.

So, it is more appropriate to use composition when integrating different components than to look for areas of overlap and develop a component tree. It will make future requirement changes manageable. If you use inheritance, it will cause a complete restructuring of the component tree.

Web components are still a very new concept and are just now gaining popularity. But, they already have undeniably significant usage in design systems and create reusable, framework-independent components that can be utilized in numerous web applications. The API is perhaps the most decisive factor when creating reusable web components and design systems. Due to this, inheritance is frequently the most appropriate approach when developing new versions of old web components. Hence, we can refer to it as “framework-level development.”

This is in contrast to application-level development, where new components are crafted to use only in certain applications and may not be applicable elsewhere. As a result, you often strive to create components for use in that application. Therefore, it is not crucial to keep an inherent API. In that case, the composition would do the needful.

The Importance of Following These Practices

The problem with inheritance is that it motivates you to go ahead and make predictions. As a result, inheritance inspires you to create a taxonomy of objects early in the project. Although it feels like we can foresee the future, humans are incapable of doing so. Thus you carry a very high risk of making critical design errors. It’s also difficult to escape the inheritance taxonomy after you’ve built yourself into it. As it’s easier to get out of the composition, it’s just better to use it from the beginning.

As a general rule, adopting inheritance is better when you’re confident that components wouldn’t evolve and you can build them with only a few levels of inheritance.

Conclusion

In some circumstances, deciding between inheritance and composition might not be easy. Therefore, it’s critical to remember that either isn’t entirely over the other. Since software project requirements tend to change over time, choosing the composition over the inheritance is recommended. Changing the code conveniently makes the applications more scalable and loosely coupled.

Build apps with reusable components like Lego

Bit’s open-source tool help 250,000+ devs to build apps with components.

Turn any UI, feature, or page into a reusable component — and share it across your applications. It’s easier to collaborate and build faster.

Learn more

Split apps into components to make app development easier, and enjoy the best experience for the workflows you want:

Micro-Frontends

Design System

Code-Sharing and reuse

Monorepo

--

--

Software Engineer | Technical Writer | BSc. IT(Hons) University of Moratuwa — Faculty of IT