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;
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! ⚡
Go to codesandbox.io
Click "Create New Sandbox"
Select "Next.js" template
Install required dependencies in the terminal:
npm install @radix-ui/react-avatar @radix-ui/react-scroll-area lucide-react
Copy the code above into a new file called DirectMessage.js in the app folder
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>
);
}
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)