Skip to Content
Lab 1

Component Creation & Props

Lab Overview

In this lab, you will create a set of reusable UI components for your company’s internal component library. You will practice creating TypeScript React components with proper prop typing, component composition, and prop handling. This lab focuses on component creation, TypeScript interfaces, prop handling, and component composition using React and TypeScript.


Workplace Context

Imagine you are a frontend developer tasked with building a component library for your company’s internal applications. Your team needs a set of reusable, type-safe components that can be easily configured for different use cases. These components will be used across multiple applications, so they need to be well-documented, properly typed, and flexible enough to handle various scenarios.

This lab will help you practice building the foundational components that will be used throughout your company’s applications.


Objectives

By the end of this lab, you will:

  1. Create reusable React components with TypeScript interfaces for props.
  2. Implement proper prop handling and validation.
  3. Use component composition effectively.
  4. Apply TypeScript best practices for component development.
  5. Document components with clear prop interfaces.

Instructions

Setup the Project

  1. Create a new React TypeScript project using Vite:
npm create vite@latest component-library -- --template react-ts cd component-library npm install
  1. Create the following folder structure:
src/ components/ AlertBox/ AlertBox.tsx AlertBox.test.tsx UserProfileCard/ UserProfileCard.tsx UserProfileCard.test.tsx ProductDisplay/ ProductDisplay.tsx ProductDisplay.test.tsx types/ index.ts

Component Requirements

1. AlertBox Component

Create an AlertBox component that can display different types of alerts (success, error, warning, info) with customizable messages.

// types/index.ts export type AlertType = 'success' | 'error' | 'warning' | 'info'; export interface AlertBoxProps { type: AlertType; message: string; onClose?: () => void; children?: React.ReactNode; }

2. UserProfileCard Component

Create a UserProfileCard component that displays user information with optional sections.

// types/index.ts export interface User { id: string; name: string; email: string; role: string; avatarUrl?: string; } export interface UserProfileCardProps { user: User; showEmail?: boolean; showRole?: boolean; onEdit?: (userId: string) => void; children?: React.ReactNode; }

3. ProductDisplay Component

Create a ProductDisplay component that shows product information with configurable display options.

// types/index.ts export interface Product { id: string; name: string; price: number; description: string; imageUrl?: string; inStock: boolean; } export interface ProductDisplayProps { product: Product; showDescription?: boolean; showStockStatus?: boolean; onAddToCart?: (productId: string) => void; children?: React.ReactNode; }

Activity Tasks

  1. Component Implementation:

    • Implement each component according to its interface requirements.
    • Use proper TypeScript types and interfaces.
    • Implement prop validation where appropriate.
    • Handle optional props and children correctly.
  2. Component Testing:

    • Test different prop combinations.
    • Verify that components render correctly with various props.
  3. Component Composition:

    • Create example usage of components working together.
    • Demonstrate prop passing between components.
    • Show how to handle component nesting.
  4. Documentation:

    • Add comments to describe component props.
    • Create example usage documentation.
    • Document any special prop handling or requirements.

Example Implementation

Here’s a starting point for the AlertBox component, using Tailwind CSS classes for styling:

// components/AlertBox/AlertBox.tsx import React from 'react'; import { AlertBoxProps } from '../../types'; export const AlertBox: React.FC<AlertBoxProps> = ({ type, message, onClose, children }) => { const alertStyles = { success: 'bg-green-100 border-green-500 text-green-700', error: 'bg-red-100 border-red-500 text-red-700', warning: 'bg-yellow-100 border-yellow-500 text-yellow-700', info: 'bg-blue-100 border-blue-500 text-blue-700' }; return ( <div className={`p-4 border-l-4 ${alertStyles[type]}`}> <div className="flex justify-between items-center"> <p>{message}</p> {onClose && ( <button onClick={onClose} className="ml-4 text-gray-500 hover:text-gray-700" > × </button> )} </div> {children} </div> ); };

Example Usage

Here are examples of how to use each component, and an example of the result:

AlertBox Example

<AlertBox type="success" message="Your profile has been updated successfully!" onClose={() => alert('Alert closed')} > <p className="text-sm">You can now continue using the application.</p> </AlertBox>

Your profile has been updated successfully!

You can now continue using the application.

UserProfileCard Example

const user = { id: '1', name: 'John Doe', email: 'john.doe@example.com', role: 'Software Engineer', avatarUrl: 'https://example.com/avatar.jpg' }; <UserProfileCard user={user} showEmail={true} showRole={true} onEdit={(userId) => alert(`Editing user ${userId}`)} > <div className="text-sm text-gray-500"> Last login: 2 hours ago </div> </UserProfileCard>

John Doe

john.doe@example.com

Software Engineer

ProductDisplay Example

const product = { id: '1', name: 'Wireless Headphones', price: 199.99, description: 'High-quality wireless headphones with noise cancellation.', imageUrl: 'https://example.com/headphones.jpg', inStock: true }; <ProductDisplay product={product} showDescription={true} showStockStatus={true} onAddToCart={(productId) => alert(`Added product ${productId} to cart`)} > <div className="text-sm text-gray-500"> Free shipping available </div> </ProductDisplay>
Wireless Headphones

Wireless Headphones

$199.99

High-quality wireless headphones with noise cancellation.

In Stock

Component Composition Example

Here’s how these components could work together:

const App = () => { const [showAlert, setShowAlert] = useState(false); const [cartItems, setCartItems] = useState<string[]>([]); const handleAddToCart = (productId: string) => { setCartItems([...cartItems, productId]); setShowAlert(true); }; return ( <div className="p-4"> {showAlert && ( <AlertBox type="success" message="Product added to cart!" onClose={() => setShowAlert(false)} /> )} <div className="grid grid-cols-1 md:grid-cols-2 gap-4 mt-4"> <UserProfileCard user={user} showEmail={true} showRole={true} /> <ProductDisplay product={product} showDescription={true} showStockStatus={true} onAddToCart={handleAddToCart} /> </div> </div> ); };

Reflection Questions

  1. How did you handle optional props in your components?
  2. What considerations did you make when designing the component interfaces?
  3. How did you ensure type safety across your components?
  4. What challenges did you face when implementing component composition?

Submission

Submit your project via a GitHub repository using the Start Assignment link on Canvas. Your submission should include:

  1. All component implementations
  2. TypeScript interfaces
  3. Example usage documentation
  4. A README.md file explaining how to use the components

Grading Criteria

Your submission will be evaluated on a complete/incomplete basis based on the following criteria:

CriteriaComplete (10 pts)Incomplete (0 pts)Points
All Required Deliverables Submitted
The learner has provided all files, documentation, or other artifacts specified in the assignment instructions (e.g., source code, README, diagrams).
No key component is missing. The assignment can be reviewed and run/tested (if applicable) with the provided materials.Missing key files or deliverables (cannot compile/run, cannot review the work).10
Essential Requirements Fulfilled
The core functionality or goals of the assignment are clearly and sufficiently addressed.
All main tasks or features explicitly stated in the prompt are at least partially implemented. The solution is runnable or reviewable without major, blocking errors. Any primary outputs match what is expected or are reasonably close to the stated requirements.Main functionalities not attempted or severely broken.10
Evidence of Original Work
The assignment must reflect the learner’s own effort, and any external resources used are properly cited.
No obvious evidence of plagiarism (e.g., copied code without citation). Any references to libraries, tutorials, or other external sources are credited in a README or comments.Significant plagiarism or uncredited copying of solutions.10

Total Points: 30