Design, Build, Extend
I like to approach the idea of designing and building a web component similar to how I have been trained to approach UX Design: following the Design Thinking Method. For those of you who are unfamiliar, the Design Thinking Method is a design approach which incentivises considering all potential aspects and perspectives of design, and applies an iterative approach to discover design components, user requirements, and refine implementation decisions. The 5 part system consists of:
- Empathize
- Define
- Ideate
- Prototype
- Test
Courtesy of the Hasso-Plattner Institute of Design at Stanford
Let's break down how these 5 steps dictated my considerations and approach when building a web component and developing on its API.
-
Empathize
- We do this innately, but in the form of web components it's important to think about the type of component you will be developing and the people that will be using it. What is the background of the people who will likely use the component? Are there any usability and/or accessibility considerations that you will need to prioritize to meet the needs of your stakeholders? The goal is to try to paint a representative picture of the types of people who could use your component, and the types of ways they may try to use it. What if you component was used in a fashion or application other than what it was intended for? Would it be able to support that user's or that developer's intentions? Becasue web components are meant to be reused and extensible, it is important to keep these concepts in mind so that you avoid developing such a restricted component that it impossible to have it apply to other needs and use cases.
-
Define
- Defining the web component and its API can be one of the most challenging parts of building a component as it is one of the most crucial parts of the entire development process. If your empathize phase has clarified a base need or functionality, this will likely indicate that your need is aligned with a base behavior that is similar to a simple HTML element or well-known component that exists on the web today. For my first web component project, I knew I was building a CTA button which immediately meant I would need to include some type of
<button>
and/or<a>
tags to complete the click and action-based events that are performed when a user clicks on a CTA button. You are then able to think about the bounds of your component. What use cases do you want to design for and support natively, and what considerations are not as crucial to your component? Maybe responsiveness for an array of different devices is crucial, but the level of animation or "flashiness" is not a huge concern because you are aiming for a minimalistic component. Situating this stance will allow you to better identify where to focus your efforts and how to plan your building process. - It is at this stage, once you have defined the bounds of your component, that you also need to consider the component's and associated element's APIs. What are the states that you need to design and implement for your component? What happens when you hover over it, or click on a button or icon? What happens when you use your keyboard to navigate to it? Is that behavior consistent with your hover behavior? Considering the states of your component will give you a better idea of the breadth required in building out the properties of you components. See the next section "Ideate" for further details on this.
- Defining the web component and its API can be one of the most challenging parts of building a component as it is one of the most crucial parts of the entire development process. If your empathize phase has clarified a base need or functionality, this will likely indicate that your need is aligned with a base behavior that is similar to a simple HTML element or well-known component that exists on the web today. For my first web component project, I knew I was building a CTA button which immediately meant I would need to include some type of
-
Ideate
- This is one of my favorite parts of designing and developing software, the ability to have free reign over iterations of the design and structure of a project or component. The goal of ideating is to creatively and iteratively enact your plan for your component, and to specifically come up with variations and styles that you think would serve as interesting approachng to your component design. As mentioned above, the properties of you component come into play between the define and ideate stages. Think about the elements of your component, considering how the could change both with a change in your component's state or to meet the design needs of another developer. For the CTA button I worked on, my team and I considered aspects such as the button icon, title, whether the button was disabled, and theme properties such as dark or high contrast mode. Using these properties for the criteria to inform how you should develop CSS variations for you component will allow you to easily "reflect" certain properties within each implementation of your component. You can think of it almost as turning on or off a lightswitch: All a developer has to do is pass a value to that property on the component and they will be able to leverage a different design or theme. The reward of ideation emerges in the implementing and use phase, but it is a crucial step in driving the flexibility and use case support of your web component.
-
Prototype
- Here is the step where you are actually building out base versions of your component in an iterative fashion. At this period of the building process, it is important to understand that there are really no "bad" approaches: this is the point where you want to build elements into your component and style them in diverse ways from what you may initially think to be the correct approach. For example, I started out my CTA button using no animations because I thought it would be distracting from the button's functioning itself. However, our team ended up implmenting a fade-to-transparent transition on our button background that looks very smooth and is still fully accessible. Try using CSS variable to make this process easier on yourself, this way you can change the text color or font in one location in code, and see this change persist throughout your entire component. This is the best way to approach using themes, as you can simply overwrite the traditional component style with a themed style simply by checking the value of a reflected property on the component in HTML. Prototyping is meant for quick and dirty development in the beginning, and wil turn into a refinement process as you develop. This is done on purpose, and allows you to focus on more intricate logic and stylistic edge cases as your prototypes become more refined and situated.
-
Test
- Our final and often most disliked component of software development: testing. Testing is so crucial for any web component, as they are specifically designed to be reusable and adaptive components of code to allow for a wide array of applications and use cases. Testing for responsive design, accessibility, state management, navicability, etc. can be a nightmare as your components become more complex and add more elements into them. This is why I highly recommend using CSS variables for quick design manipulation, as well as the use of Storybook. Storybook functions as a customizable design library which easily lets developers implement and test different states, formats, and styles of their component side-by-side in one compact demo platform. It acts more as a visual testing platform, but allows for easy iteration and design management in later steps of the component development process.
- It is also crucial to write programming logic tests yourself as well. I won't go into this much, but it is crucial to understand whether certain content or data types will impact the functionality of your component. Most of this testing comes down to logic handling and edge-case recognition to see long-term benefits, but writing tests for your components will assure you are supporting a consistent experience across different states and use cases.
Component Breakdown
- Naturally, your component will need to be broken down into its constituent parts based on the modularity and flexibility that your design requirements specify, as well as based on the actual HTML structure of your component. The more complex your component, and the higher number of nested HTML tags, the all the more crucial it is to scaffold out a clear structure of how each element behaves. For example, my first web component involved designing a CTA button. This button consisted of a
<button>
tag with an<a>
tag wrapped around it. The purpose of wrapping the button instead of using only a button tag was to allow the CTA button to function as a button that acts more as a hyperlink than a traditional button. The use case dictated that the button needed to open a completely new URL in a new browser tab, so it made more sense to nest the button tag so that the href used for the hyperlink could be attached across the entire button as well as any other elements that needed to be added to the button. If you wanted to add other clickable elements to the button in the future, it is as simple as nesting those elements at the same level as the button inside the<a>
tag. - The point of this example is to show that the way you structure and nest elements plays a huge role in the complexity of your CSS and the readability of your code. Poor element structuring can lead to messy CSS with dense logic to control different states, whereas a structured component like my CTA button allows for very simple implementation and customization as necessary by anyone intending to use the component.
- Another component I am now working on consists of building a card web component. What is unique about the card compared to the initial button component I worked on is the fact that a card is a container of smaller elements. These smaller elements include a banner, content body, and an extensible icon. Our team was provided with a starter component that includes a basic scaffold of a card containing text and images, and demos a few different examples of the card's scaffolding to depict how the use of the type keyword can allow for matching of card CSS styles to a specific card tag itself. The component is expected to use the button I have assisted in developing previously as a devDependency to demo interactivity of the card component. The component will utilize LitElement properties and Lifecycle functions to keep track of updating the behavior of the card based on each state and property value.
- For this component, it will be crucial to consider how each of these element's designs and dimensions will be leveraged together to allow for a cohesive stylistic experience when interacting with the card. For example, accessibility when users navigate with a keyboard through each of the elements is paramount, as we will need to be sure that a logical tab path allows for interaction with any actionable elements on the card. Another example would be the behavior of the card when a user clicks an item within the bounds of the component. We play to support a sliding card with hidden content behind the front pane, so it will be important in our scaffolding implementation to assure that selection of content inside the card will bubble up content and focus to the front pane of the card after click event occurs.
Provided Card Example
Expected Difficulties
- Building web components is hard: there I said it. Handling the vast number of states, properties, design edge cases, logic edge cases, and behaviors while supporting the extensibility that you desire for your component means much of your time will be spent writing specific CSS and monitoring how you pass properties into your component. One of the greatest challenges I faced was structuring my CSS in a way that targeted specific states without overwriting other states or thematic behavior. If you have a poorly scaffolded component in the define and ideate stages, you will really struggle to reflect the visual aspects you want to have on your component behave the way it should in a readable manner.
- Another difficulty I faced was with deciding when my prototype was "complete". I would argue that a web component is never really complete, perhaps by design, but it can be hard to know when it is ready to ship as a usable component. I found myself considering more complex state logic and subsequent stylistic behavior of my CSS button, but realized these ideas were more than I needed to support given the purpose of the CTA button in the first place. This doesn't mean you shouldn't extend and update your components, or at least build in support for this customization, but that you should take this into account during ideation so you minimize the risk of scope creep.
Reflection on my First Experience
- Overall, my first experience developing a web component was an incredibly rewarding learning experience. I didn't really realize the complexity of considerations that went into designing something as "simple" as a button, so it gives me a great deal of respect for the designers and developers responsible for building our entire design systems and libraries at larger companies. These guides can become thousands of components and states as use cases become more precise, so having the forethought to look into how to ideate early while keeping a component's scalability in mind was a really valuable perspective to adopt as I continue into my professional career. It really comes down to motivation and consistency. The future of the web is component-based, and I think it is a highly valuable skill to bring component knowledge to your place of work as a front-end engineer. The modularity of web components really is the future of the web, and I think this will allow for a more simplistic customization process in the future of web design.
- It became easier for me to understand how components can relate to larger components within a webpage, and how explicit component-based design can make it very easy to support additional requirements and use cases within a system later on. Compared to a "one-and-done" UI development approach, web components make this experience of designing for the future night-and-day.
- Finally, I recommend working with partners when you are developing a component or set of components. You are really limited to your own mental model, which greatly restricts the use cases and value you may place on certain development decisions of a web component. Collaborating with others lets you test ideas more quickly, promotes your group to experiment and make mistakes, and will ultimately make you aware of more features and nuances of the platform you are using, whether that be LitElement or a JS framework such as React or Vue.
Please take a look into building your first web component! It's a fun and rewarding experience that creates a more customizable and inclusive internet for all.
Here's my group's button if you're interested: https://www.npmjs.com/package/@table-in-the-corner/invisi-button
Top comments (0)