Web Development with Claude Sonnet 3.5

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.