DEV Community

Cover image for How to Build a Modern Direct Message Component in React | Daily UI Challenge Day 13
Johnny Santamaria
Johnny Santamaria

Posted on

How to Build a Modern Direct Message Component in React | Daily UI Challenge Day 13

Another day, another UI challenge! Today we're tackling a Direct Message interface - a feature that's become essential in modern applications. I decided to create a clean, minimal DM component that focuses on the core functionality while maintaining a modern aesthetic.

The Challenge 🎯

Create a Direct Message interface that's intuitive and visually appealing. The interface should include:

  • Message history
  • Input field for new messages
  • User status indicators
  • Timestamp displays

The solution 💡

I built this using React with Tailwind CSS and shadcn/ui components for a polished look. Let's dive into the code!

import React, { useState } from 'react';
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import { Send } from 'lucide-react';
import { ScrollArea } from '@/components/ui/scroll-area';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';

const DirectMessage = () => {
  const [messages, setMessages] = useState([
    {
      id: 1,
      sender: 'Sarah Parker',
      content: 'Hey! How's the UI challenge going?',
      timestamp: '10:32 AM',
      isMe: false,
    },
    {
      id: 2,
      sender: 'Me',
      content: 'Making progress! Working on the DM interface right now.',
      timestamp: '10:34 AM',
      isMe: true,
    },
  ]);
  const [newMessage, setNewMessage] = useState('');

  const handleSend = () => {
    if (newMessage.trim()) {
      setMessages([
        ...messages,
        {
          id: messages.length + 1,
          sender: 'Me',
          content: newMessage,
          timestamp: new Date().toLocaleTimeString([], { 
            hour: '2-digit', 
            minute: '2-digit'
          }),
          isMe: true,
        },
      ]);
      setNewMessage('');
    }
  };

  return (
    <div className="w-full max-w-md mx-auto h-[600px] bg-white rounded-lg shadow-lg flex flex-col">
      {/* Header */}
      <div className="p-4 border-b flex items-center space-x-3">
        <Avatar>
          <AvatarImage src="/api/placeholder/32/32" alt="Sarah" />
          <AvatarFallback>SP</AvatarFallback>
        </Avatar>
        <div>
          <h3 className="font-semibold">Sarah Parker</h3>
          <span className="text-sm text-green-500">Online</span>
        </div>
      </div>

      {/* Messages */}
      <ScrollArea className="flex-1 p-4">
        <div className="space-y-4">
          {messages.map((message) => (
            <div
              key={message.id}
              className={`flex ${message.isMe ? 'justify-end' : 'justify-start'}`}
            >
              <div
                className={`max-w-[70%] rounded-lg p-3 ${
                  message.isMe
                    ? 'bg-blue-500 text-white'
                    : 'bg-gray-100 text-gray-900'
                }`}
              >
                <p>{message.content}</p>
                <span className="text-xs opacity-70 mt-1 block">
                  {message.timestamp}
                </span>
              </div>
            </div>
          ))}
        </div>
      </ScrollArea>

      {/* Input Area */}
      <div className="p-4 border-t flex space-x-2">
        <Input
          value={newMessage}
          onChange={(e) => setNewMessage(e.target.value)}
          placeholder="Type a message..."
          className="flex-1"
          onKeyPress={(e) => e.key === 'Enter' && handleSend()}
        />
        <Button onClick={handleSend}>
          <Send className="h-4 w-4" />
        </Button>
      </div>
    </div>
  );
};

export default DirectMessage;

Enter fullscreen mode Exit fullscreen mode

Key Features ⭐

  • Clean Interface: The design maintains a minimal aesthetic while providing all necessary functionality.

  • Real-Time Updates: Messages are added instantly to the conversation when sent.

  • Responsive Design: The component adapts well to different screen sizes while maintaining usability.

  • Visual Hierarchy: Different message states (sent vs received) are clearly distinguished through color and positioning.

  • User Status: Online/offline status is clearly visible in the header.

Design Decisions 🎨

  • Used a blue accent color for sent messages to create clear visual distinction

  • Implemented a scrollable message area for better space utilization

  • Added timestamps to each message for context

  • Included user avatar and status for better user experience

  • Made the input area sticky at the bottom for easy access

Learning Points 📚

This challenge helped reinforce several important UI/UX principles

  • The importance of clear visual feedback for user actions

  • How to maintain consistency in spacing and alignment

  • The value of subtle animations for interaction feedback

  • Proper handling of different message lengths and types

Next steps 🚀

If I were to expand this further, I might add:

  • Message delivery status indicators

  • Typing indicators

  • File attachment support

  • Emoji picker

  • Message reactions

Try it yourself! ⚡

  1. Go to codesandbox.io

  2. Click "Create New Sandbox"

  3. Select "Next.js" template

  4. Install required dependencies in the terminal:

npm install @radix-ui/react-avatar @radix-ui/react-scroll-area lucide-react
Enter fullscreen mode Exit fullscreen mode
  1. Copy the code above into a new file called DirectMessage.js in the app folder

  2. Update your page.js to import and use the component:

import DirectMessage from './DirectMessage';

export default function Home() {
  return (
    <div className="min-h-screen p-8 bg-gray-100">
      <DirectMessage />
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

Why codesandbox.io? 🤔

  • Zero Setup: No need to install anything locally - just open your browser and start coding

  • Real-time Preview: See your changes instantly as you type

  • Built-in Dependencies: Easy to add and manage npm packages

  • Sharing Made Simple: Get a shareable link instantly to collaborate with others

  • Great for Prototyping: Perfect for quick UI experiments and demos like this one

Conclusion

This Direct Message interface combines functionality with clean design principles. While keeping it minimal, it still provides all the essential features users expect from a modern messaging interface.

What do you think about this implementation? I'd love to hear your thoughts and suggestions for improvement!


Tools used: React, Tailwind CSS, shadcn/ui
Part of the #DailyUI challenge - Day 13

Top comments (0)