DEV Community

Cover image for Applying the open-closed principle to UI components
David
David

Posted on • Originally published at learnitmyway.com

3 1

Applying the open-closed principle to UI components

In this article, I will demonstrate a simple example of applying the open/closed principle to a UI component in React or Angular.

Background

I had an aha moment this week regarding the open/closed principle, which states "software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification" and is the O in SOLID. I have always found this principle to be quite abstract and I didn't know if I was applying it until now.

The aha moment came to me when I wanted to change the style of an existing component. For simplicity's sake, let's say this was a button and I wanted to change the existing background colour. Let's see how this works in React and then Angular. Or you can skip straight to Angular.

React

Link to source code.

I will start with a simple button component:

// src/Button.js
import React from 'react'
import './Button.css'

const Button = () => (
  <button className="Button" type="button">
    Click Me!
  </button>
)

export default Button

that has the background color aliceblue:

/* src/Button.css */
.Button {
  background-color: aliceblue;
}

and is used as follows:

// src/App.js
import React from 'react'
import './App.css'
import Button from './Button'

const App = () => (
  <div className="App">
    <Button />
  </div>
)

export default App

Now our app's stakeholders have said they would like us to add a new button in papayawhip directly beside the existing button. They have also said there are more buttons to follow. So I parameterise the className in the Button component:

// src/Button.js
import React from 'react'

const Button = ({ className }) => (
  <button className={className} type="button">
    Click Me!
  </button>
)

export default Button

and then use it as follows:

// src/App.js
import React from 'react'
import './App.css'
import Button from './Button'

const App = () => (
  <div className="App">
    <Button className="button-aliceblue" />
    <Button className="button-papayawhip" />
  </div>
)

export default App

By passing className to Button as a prop I can update (extend) the styles without changing (modifying) the Button component:

/* src/App.css */
.button-aliceblue {
  background-color: aliceblue;
}

.button-papayawhip {
  background-color: papayawhip;
}

This just fulfilled the open/closed principle!

CSS-in-React

A similar approach can also be used with styled-components.

Angular

Link to source code.

I will start with a simple button component:

// src/app/button/button.component.ts 
import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-button',
  templateUrl: './button.component.html',
  styleUrls: ['./button.component.css'],
})
export class ButtonComponent {}
<!-- src/app/button/button.component.html -->
<button class="button" type="button">Click me!</button>

that has the background color aliceblue:

/* src/app/button/button.component.css */
.button {
  background-color: aliceblue;
}

and is used as follows:

<!-- src/app/app.component.html -->
<div class="content" role="main">
  <app-button></app-button>
</div>

Now our app's stakeholders have said they would like us to add a new button in papayawhip directly beside the existing button. They have also said there are more buttons to follow. So I parameterise the style of the Button component (I would have preferred to parameterise the CSS class name, like in the React example above, but I couldn't figure out how to do it):

// src/app/button/button.component.ts 
import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-button',
  templateUrl: './button.component.html',
  styleUrls: ['./button.component.css'],
})
export class ButtonComponent {
  @Input() style: { [index: string]: string };
}

and then use it as follows:

<!-- src/app/button/button.component.html -->
<button [ngStyle]="style" type="button">Click me!</button>

By passing style to app-button as a property I can add a button and update (extend) the styles without changing (modifying) the app-button component:

<!-- src/app/app.component.html -->
<div class="content" role="main">
  <app-button
    [style]="{
      backgroundColor: 'aliceblue'
    }"
  ></app-button>
  <app-button
    [style]="{
      backgroundColor: 'papayawhip'
    }"
  ></app-button>
</div>

This just fulfilled the open/closed principle!

Final Thoughts

I hope this simple example has helped you understand how the open/closed principle can be applied to UI components. Feel free to look at the source code in React or Angular.

Heroku

Simplify your DevOps and maximize your time.

Since 2007, Heroku has been the go-to platform for developers as it monitors uptime, performance, and infrastructure concerns, allowing you to focus on writing code.

Learn More

Top comments (0)

Qodo Takeover

Introducing Qodo Gen 1.0: Transform Your Workflow with Agentic AI

Rather than just generating snippets, our agents understand your entire project context, can make decisions, use tools, and carry out tasks autonomously.

Read full post

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay