In this module, you'll learn how to create reusable components using JavaScript. Components are self-contained, reusable pieces of code that represent a part of the user interface. You'll understand component composition, state management, and best practices for building maintainable components that can be combined to create complex UIs while keeping code organized and DRY (Don't Repeat Yourself).
Learn about creating component functions that return DOM elements and how to compose them. Component functions encapsulate the logic for creating and configuring elements, making your code more modular and easier to maintain. You'll learn how to structure these functions to create consistent, reusable interface elements.
A component comprises several parts: HTML, CSS, or JavaScript brought together for reuse in a website or application. Components help you organize your code, make it reusable, and simplify maintenance.
When building HTML with a component mentality, you need to ask the question: "What am I trying to display from my data?"
Because we are focused on user interface concepts, we don't need to access a database at this point. For us, static HTML is data since it is, after all, what we're trying to display.
Example of repeating elements that could become a component:
<div class="custom-buttons">
<button>Button 1</button>
<button>Button 2</button>
<button>Button 3</button>
<button>Button 4</button>
</div>
This is an opportunity to think about using our CSS and JavaScript to create multiple buttons regardless of how many buttons we have to work with. The HTML gives us a great starting point for a button component, but we need to style it for reuse.
Learn how to create components that return complex DOM hierarchies. This technique allows you to build sophisticated UI components with proper parent-child relationships, nested elements, and organized structure. You'll see how a single component function can create an entire section of your interface with proper structure.
Components often need to create a nested hierarchy of elements. A component function can return a parent element that contains multiple children, creating a complete UI structure with a single function call.
Example of a function that creates a card component:
function createCard(title, content, imageUrl) {
// Create the container
const card = document.createElement('div');
card.classList.add('card');
// Create the image (if provided)
if (imageUrl) {
const img = document.createElement('img');
img.src = imageUrl;
img.alt = title;
img.classList.add('card-image');
card.appendChild(img);
}
// Create the title
const titleElement = document.createElement('h2');
titleElement.textContent = title;
titleElement.classList.add('card-title');
card.appendChild(titleElement);
// Create the content
const contentElement = document.createElement('p');
contentElement.textContent = content;
contentElement.classList.add('card-content');
card.appendChild(contentElement);
return card;
}
This function can then be used to create multiple card instances with different content:
const card1 = createCard('First Card', 'This is the content for card 1', 'image1.jpg');
const card2 = createCard('Second Card', 'This is the content for card 2', 'image2.jpg');
document.querySelector('.cards-container').appendChild(card1);
document.querySelector('.cards-container').appendChild(card2);
Learn how to add event listeners and interactivity to your components. This crucial step transforms static DOM elements into interactive components that respond to user actions. You'll explore techniques for adding event handlers within component creation functions, making your components self-contained with both structure and behavior.
JavaScript is used to consume the data and output the content into the DOM. JavaScript's involvement in components is the glue that ties everything together. We can use Javascript to consume the HTML and return a component version of it!
When creating interactive components, you need to:
Example of an interactive button component:
function createInteractiveButton(text, clickHandler) {
// Create the button
const button = document.createElement('button');
button.textContent = text;
button.classList.add('custom-btn');
// Add event listener for interactivity
button.addEventListener('click', clickHandler);
return button;
}
// Usage
const button = createInteractiveButton('Click Me', function() {
console.log('Button was clicked!');
// Additional functionality
});
// Attach to the DOM
document.querySelector('.button-container').appendChild(button);
Components can also maintain internal state and update themselves when that state changes, which is a more advanced pattern often seen in component libraries and frameworks.
Learn how to use data to dynamically generate DOM elements in your components. This powerful technique allows components to adapt based on the data they receive, enabling you to create dynamic lists, tables, galleries, and other data-driven UI elements. You'll practice using array methods like map and forEach to transform data into DOM structures.
Writing CSS for components is more about rationale than syntax. Components should be modular or stand-alone. With that in mind, you should try to think of your component CSS in a way that could be moved around at any moment and not reliant on any other styles being in place.
One way that can help you control your styles is to use a specificity chain that only matches up with your component. You could use a specific class name to accomplish this:
<div class="custom-buttons">
<button class="custom-btn">Button 1</button>
<button class="custom-btn">Button 2</button>
<button class="custom-btn">Button 3</button>
<button class="custom-btn">Button 4</button>
</div>
Real-world applications often need to render lists of items based on data from an API or other source. We can use array methods to transform data into DOM elements:
// Sample data
const products = [
{ id: 1, name: 'Product 1', price: 19.99, inStock: true },
{ id: 2, name: 'Product 2', price: 29.99, inStock: false },
{ id: 3, name: 'Product 3', price: 39.99, inStock: true }
];
// Component function for a single product
function createProductItem(product) {
const item = document.createElement('div');
item.classList.add('product-item');
item.dataset.id = product.id;
const name = document.createElement('h3');
name.textContent = product.name;
const price = document.createElement('p');
price.textContent = `$${product.price}`;
const stockStatus = document.createElement('span');
stockStatus.textContent = product.inStock ? 'In Stock' : 'Out of Stock';
stockStatus.classList.add(product.inStock ? 'in-stock' : 'out-of-stock');
item.appendChild(name);
item.appendChild(price);
item.appendChild(stockStatus);
return item;
}
// Render the product list
function renderProductList(products, containerSelector) {
const container = document.querySelector(containerSelector);
// Clear previous content
container.innerHTML = '';
// Create a document fragment for better performance
const fragment = document.createDocumentFragment();
// Add each product to the fragment
products.forEach(product => {
const productElement = createProductItem(product);
fragment.appendChild(productElement);
});
// Add all products to the DOM in a single operation
container.appendChild(fragment);
}
// Usage
renderProductList(products, '.products-container');
This approach allows you to update the UI whenever the data changes, simply by calling the render function again with the updated data.