Component thinking in design and development
Dive into the heart of web development, where components ingeniously marry functionality and aesthetics. Explore how these essential bricks of code can revolutionise user interaction, making every experience both more intuitive and more engaging.
Components play a fundamental role in web development today. They allow developers to build and reuse smaller or larger chunks of code that can be assembled to create complex user interfaces. In this article, we'll look at what technically defines a component, the benefits of using them and the link between components in design and those in development.
What is a component?
Technically speaking, a component is an independent code module that encapsulates a specific functionality. The main characteristics of a component are that it must :
- be reusable
- be potentially modular, with certain properties in particular,
- follow a naming convention,
- be easy to understand and use.
In simple terms, to design a function, you need to imagine it and break it down into 'bricks' which are then linked together. A component is therefore a brick of code, which can be used and reused in various places in the application. In design terms, a component is basically an element that responds to a user need, so it is often interactive or used to communicate with the user.
Why use components in development?
Breaking code down into components offers a number of advantages:
- Centralising, the code is grouped together in one place.
- Reducing the amount of code, centralising the code implicitly means reducing the amount of code supplied, as there is no longer any duplication.
- Limit the potential for bugs, because if you imagine the same code being used in several places without being centralised, and you modify it in one place but not in the others, bugs can occur. Centralising the code allows you to make a single change, which will be effective everywhere.
- Better understanding, less volume often means better understanding.
- Be scalable, as an application grows in complexity, components can be combined and reused to create more complex interfaces. This makes it easier to manage large code bases and maintain a consistent user experience.
One of the only 'drawbacks' of this approach is the potential for more files/folders, and therefore a project architecture that requires a great deal of organisation to find its way around. At Atipik, we prefer to use design systems for projects involving a large number of components.
Why use components in design?
In the same way, when designing a product, it is very interesting to use components. The main advantages include:
- Bringing consistency to the user experience, having components with the same style and interaction throughout the application means that the interface is consistent and simple to use.
- Being scalable, being able to follow the evolution of the product and adapt to new user needs.
- Reduce effort, by centralising the styling of components, you can make changes in the blink of an eye and apply them to all views of the application at the same time.
- Limiting style inconsistencies, eliminating the need to duplicate styles means that any design updates do not have to be applied everywhere. A single location is all you need, and this limits, if not prevents, inconsistencies in views.
The most important positive point for me is that, combined, these approaches to design AND development lead to better understanding and more fluid communication between designers and developers. Indeed, by using the same terms, the same names and the same properties for components, it greatly simplifies the work of the developer in implementing the design specifications. Not to mention the time saved when it comes to updating the design. For example, let's imagine a "Button" component. If the design changes, as a developer you don't need to look for where to make the change, you go straight to the Button component file.
There are a number of tools for building user interfaces using components, the best known of which are probably Figma (which we use at Atipik), Sketch and Adobe XD. The advantage of Figma is that it makes it easier for members of a team to collaborate, in particular through the ability to work in real time with designers or developers (comments, design sharing, real-time modifications, etc.).
Practical example of the use of components
Context of the example: we want to have a list of the different products we have in stock. A search field is provided to filter the list. The design, which is very simplistic because it has little importance here, will look like this:
As soon as you see or imagine a feature (like in our case), your first instinct should be to notice the elements that seem to repeat themselves. Then, you can turn them into reusable components.
Here, what stands out is the list of products. The list always displays the same types of values in the same order: product name, price. So it makes sense to create a component that takes a product as a parameter and displays the same information.
For the example, I'm using version 3 of the Vue framework. This first component will be as follows:
// src/components/ProductListItem.vue
<script setup>
const props = defineProps({
// the product parameter passed to the component
product: {
type: Object,
required: true,
},
});
</script>
<template>
<tr>
<td>
{{ product.name }}
</td>
<td>{{ product.price }}€</td>
</tr>
</template>
Next, we organize the architecture by deciding to group the list display into a component. This component will take a parameter with the list of products to display. We'll then iterate through this list using our existing component to display each product individually. This results in:
// src/components/ProductList.vue
<script setup>
import { computed } from "vue";
import ProductListItem from "./ProductListItem";
const props = defineProps({
// we pass in parameter the products list to display
products: {
type: Array,
required: true,
},
});
</script>
<template>
<table class="list-table">
<thead>
<tr>
<th>Name</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<ProductListItem
v-for="product in products"
:key="product.name"
:product="product"
/>
</tbody>
</table>
</template>
<style scoped>
.list-table {
margin-top: 1rem;
text-align: left;
border-collapse: collapse;
}
.list-table th {
border-bottom: solid 1px black;
}
</style>
Then, the last potentially reusable component here would be the search field. One might say that neither the list nor the search field is reused here. However, the question should always be asked whether there is a potential for reuse later in other functionalities. Here, we realise that a search field and a list of products can potentially be displayed and used in other places in the code.
So we create our search field :
// src/components/MyInput.vue
<script setup>
import { computed } from "vue";
const props = defineProps({
valueModel: {
type: String,
required: true,
},
});
const emit = defineEmits(["update:valueModel"]);
const value = computed({
get() {
return props.valueModel;
},
set(newValue) {
emit("update:valueModel", newValue);
},
});
</script>
<template>
<input v-model="value" class="my-input" />
</template>
<style scoped>
.my-input {
border: solid 1px black;
outline: none;
border-radius: 5px;
padding: 0.2rem 0.4rem;
}
.my-input:focus {
border-color: rgb(46, 168, 250);
}
</style>
Finally, we use our components in our main file, here App. This file will contain the value of our product list, passed to the dedicated component, and the value of the search field, used to filter the list.
// src/App.vue
<script setup>
import ProductList from "./components/ProductList";
import MyInput from "./components/MyInput";
import { ref, watch } from "vue";
const searchValue = ref("");
const products = ref([
{ name: "Pencil", price: 5.5 },
{ name: "Rubber", price: 3.9 },
{ name: "Ruler", price: 8.2 },
{ name: "Cisors", price: 12 },
]);
</script>
<template>
<div class="container">
<MyInput
v-model:valueModel="searchValue"
placeholder="Search a product..."
/>
<ProductList
:products="
products.filter((product) =>
product.name.toLowerCase().includes(searchValue.toLowerCase())
)
"
/>
</div>
</template>
<style>
.container {
display: flex;
flex-direction: column;
max-width: 15rem;
}
</style>
That's it! Now, what happens if the design changes and we no longer want the price in black but in orange ? There is only one thing to do :
// we head into the concerned component file : src/components/ProductListItem.vue
// then we change from this line of code :
<td>{{ product.price }}€</td>
// to this :
<td style="color: orange">{{ product.price }}€</td>
Our price is now displayed in orange on all products.
Limitations of components
Although the use of components has many advantages, it would be wrong to say that it is a perfect system.
In fact, although components allow you to group together a common behaviour for the elements of an application, they can quickly become cumbersome as soon as the complexity of the application increases. For example, a 'select' (or 'dropdown') component can quickly include complex logic that is specific to certain cases (simple/multiple select, taking into account arrays/character strings/objects as values, groups, customisation of items in the list, etc.). There can quickly be many special cases and this can lead to undesirable side effects, particularly in places where the component is already in use.
What's more, as a project grows, the number of components can increase dramatically, making them difficult to manage. A good organisation/structure is therefore absolutely essential.
Conclusion
Components are a powerful tool for developers and designers alike. They provide a common language and a forum for exchange. In particular, they improve efficiency and communication between the two teams. However, it is important to do this in the right way, using the same names, attributes, etc., for example.
Once the right conditions are in place, project development will be all the faster and more efficient.
Jérémy
Software Engineer · Web