Web Development with Claude Sonnet 3.5

Web development with Claude AI
AI in the modern web development process
Mauto 5 min

After exploring code optimization, let’s see how Claude can help us with web development. From building frontend components to debugging APIs, Claude excels at analyzing and generating web code.

Responsive Frontend Development

Dev: I need to build a responsive card component for a blog. Requirements:
- Featured image
- Title
- Excerpt
- Date and author
- Grid layout on desktop, single column on mobile

Claude: Let's build a component using CSS Grid and flexbox for responsiveness. Here's a first version:
<article class="blog-card">
  <img src="{{post.image}}" alt="{{post.title}}" class="card-image">
  <div class="card-content">
    <h2 class="card-title">{{post.title}}</h2>
    <div class="card-meta">
      <time>{{post.date}}</time>
      <span class="author">{{post.author}}</span>
    </div>
    <p class="card-excerpt">{{post.excerpt}}</p>
  </div>
</article>

<style>
.blog-card {
  display: grid;
  gap: 1rem;
  background: #fff;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}

/* Mobile first */
.card-image {
  width: 100%;
  height: 200px;
  object-fit: cover;
}

/* Desktop layout */
@media (min-width: 768px) {
  .blog-card {
    grid-template-columns: 1fr 2fr;
  }
  
  .card-image {
    height: 100%;
  }
}
</style>
Dev: I'd add a hover effect and smooth animations

Claude: Here's the version with hover effects and transitions:
<style>
.blog-card {
  display: grid;
  gap: 1rem;
  background: #fff;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.blog-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 8px 24px rgba(0,0,0,0.15);
}

.card-image {
  width: 100%;
  height: 200px;
  object-fit: cover;
  transition: transform 0.5s ease;
}

.blog-card:hover .card-image {
  transform: scale(1.05);
}

.card-title {
  position: relative;
  padding-bottom: 0.5rem;
}

.card-title::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  width: 0;
  height: 2px;
  background: currentColor;
  transition: width 0.3s ease;
}

.blog-card:hover .card-title::after {
  width: 100%;
}
</style>
Dev: How would I make it accessible?

Claude: Here's the version with accessibility improvements:
<article class="blog-card" tabindex="0">
  <img 
    src="{{post.image}}" 
    alt="{{post.imageDescription}}" 
    class="card-image"
    loading="lazy"
  >
  <div class="card-content">
    <h2 class="card-title">
      <a href="{{post.url}}" 
         class="card-link"
         aria-label="Read the article: {{post.title}}"
      >
        {{post.title}}
      </a>
    </h2>
    <div class="card-meta" aria-label="Article details">
      <time datetime="{{post.date.iso}}">{{post.date.formatted}}</time>
      <span class="author">by {{post.author}}</span>
    </div>
    <p class="card-excerpt">{{post.excerpt}}</p>
  </div>
</article>

<style>
.blog-card {
  /* ... previous styles ... */
}

/* Focus styles */
.blog-card:focus-within {
  outline: 3px solid #4A90E2;
  outline-offset: 2px;
}

.card-link {
  color: inherit;
  text-decoration: none;
  outline: none;
}

.card-link:focus {
  text-decoration: underline;
  text-underline-offset: 4px;
}

/* Reduce motion if requested */
@media (prefers-reduced-motion: reduce) {
  .blog-card,
  .card-image,
  .card-title::after {
    transition: none;
  }
}
</style>

Backend: RESTful APIs

Dev: I need to build an API to manage orders for an e-commerce site. Can you help me define the structure?

Claude: Let's start with the main RESTful endpoints for order management:
// types.ts
interface OrderItem {
  productId: string;
  quantity: number;
  price: number;
}

interface Order {
  id: string;
  userId: string;
  items: OrderItem[];
  status: 'pending' | 'confirmed' | 'shipped' | 'delivered';
  shippingAddress: Address;
  paymentInfo: PaymentInfo;
  createdAt: Date;
  updatedAt: Date;
}

// orders.controller.ts
@Controller('orders')
export class OrdersController {
  @Post()
  @UseGuards(AuthGuard)
  async createOrder(@Body() order: CreateOrderDto) {
    return this.orderService.create(order);
  }
  
  @Get('user/:userId')
  @UseGuards(AuthGuard)
  async getUserOrders(
    @Param('userId') userId: string,
    @Query() filters: OrderFilters
  ) {
    return this.orderService.findByUser(userId, filters);
  }
  
  @Patch(':orderId/status')
  @UseGuards(AuthGuard, RolesGuard)
  @Roles('admin')
  async updateOrderStatus(
    @Param('orderId') orderId: string,
    @Body('status') status: OrderStatus
  ) {
    return this.orderService.updateStatus(orderId, status);
  }
}
Dev: How do I handle notifications when the order status changes?

Claude: Let's implement an event system with multiple notifications:
// events/order-status.event.ts
export class OrderStatusChangedEvent {
  constructor(
    public readonly orderId: string,
    public readonly oldStatus: OrderStatus,
    public readonly newStatus: OrderStatus,
    public readonly userId: string
  ) {}
}

// notifications/order.listener.ts
@Injectable()
export class OrderNotificationListener {
  @OnEvent('order.status.changed')
  async handleStatusChange(event: OrderStatusChangedEvent) {
    const notifications = await Promise.all([
      this.emailService.sendStatusUpdate(event),
      this.pushService.sendNotification(event),
      event.newStatus === 'shipped' && 
        this.smsService.sendTrackingInfo(event)
    ]);
    
    await this.logNotifications(event, notifications);
  }
}

// orders.service.ts
@Injectable()
export class OrdersService {
  async updateStatus(orderId: string, newStatus: OrderStatus) {
    const order = await this.findById(orderId);
    
    const event = new OrderStatusChangedEvent(
      orderId,
      order.status,
      newStatus,
      order.userId
    );
    
    await this.orderRepository.update(orderId, { status: newStatus });
    await this.eventEmitter.emit('order.status.changed', event);
    
    return this.findById(orderId);
  }
}

Testing and Debugging

When we write tests, Claude can help us identify edge cases:

Dev: I need to test the order system, which cases should I consider?

Claude: Here's a complete test suite:
describe('OrdersService', () => {
  describe('createOrder', () => {
    it('creates an order with valid products', async () => {
      // Basic test
    });
    
    it('handles unavailable products', async () => {
      // Check stock errors
    });
    
    it('correctly calculates totals and discounts', async () => {
      // Check calculations
    });
    
    it('validates the shipping address', async () => {
      // Validation test
    });
  });
  
  describe('updateStatus', () => {
    it('notifies the user of the status change', async () => {
      // Check notifications
    });
    
    it('prevents invalid status transitions', async () => {
      // E.g.: from pending to delivered
    });
    
    it('handles notification errors with retry', async () => {
      // Resilience test
    });
  });
});

Continuous Integration

Claude can suggest optimized CI workflows:

Dev: How do I set up CI for this project?

Claude: Here's a complete GitHub Actions configuration:
name: E-commerce API CI

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    
    services:
      postgres:
        image: postgres:14
        env:
          POSTGRES_USER: test
          POSTGRES_PASSWORD: test
          POSTGRES_DB: test_db
        ports:
          - 5432:5432
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
          
    steps:
    - uses: actions/checkout@v3
    
    - name: Setup Node.js
      uses: actions/setup-node@v3
      with:
        node-version: '18'
        cache: 'npm'
        
    - name: Install dependencies
      run: npm ci
      
    - name: Lint
      run: npm run lint
      
    - name: Type check
      run: npm run type-check
      
    - name: Unit tests
      run: npm test
      
    - name: E2E tests
      run: npm run test:e2e
      env:
        DATABASE_URL: postgresql://test:test@localhost:5432/test_db

Conclusion

Web development with Claude requires clearly communicating your requirements and an iterative refinement process. In the next article we’ll explore using Claude for machine learning.

Copiato