Creating chat interface without profile image like Twitch or Telegram in React!

Forcing your users to upload their Profile Image while sign up is bit annoying for the user's experience. Also have to save the user profile picture might cost you bit higher in your final cost.
Just by not asking users to upload their profile image while sign up or give an option to skip profile image customization, you'll gain some benefit like:
- Better UX
- Lower storage usage
- Faster load time in the frontend
But it's also will sacrifice the UI (User Interface) if we didn't do it correctly. Using Gravatar might be a good option, but for me personally, it's way more annoying that I had the same face everywhere, and sometimes I don't wanna use my real face at all in some website or app.
I didn't say Gravatar is bad, but just imagine if I had LinkedIn and Myanimelist account and both are using Gravatar, it will be awkward in so many cases.
Alternatively using
?d=identiconin Gravatar is way better than using real face, but it's not the best looking things to be honest
Profile picture can serve different purpose, like in Discord I want my profile picture to be funny and cheerful because it's the place where I do gaming and go along with my friends, and if it's LinkedIn I want my profile to look professional as possible without losing my character.
I love how some Job Finder website put a little tie in their users default profile image so it could give an impression of professionality as what the users supposed to have.

But the best approach I like is Telegram, they put user's first name and last name letter, and then combined, give a unique color, and you got a unique profile picture.
By given unique color it's also applied at the name in the bubble chat too.
Unlike Telegram, Twitch only use unique color to identify each user instead profile picture, and it's really good both for user experience and performance so people will quickly identified based on the color. it's not the best looking things but it's really good for performance because Twitch chat can go really crazy especially for big stream with hundred of viewers.

So, I think using unique color is a best approach to identify each user.
Then how do we approach that? The most obvious way is to generate random color and save it along with the user data. But, it will cost you a couple byte in your database that actually can be reduced.
There's a library called seed-to-color that I like to use in the scenario, it's a library I created to give random color base on the seed given in the parameter. Let's try to built one with it.
First add seed-to-color to your project
yarn add seed-to-color
or
npm i seed-to-color
Then import it in the project
import { randomLightColor, randomDarkColor, randomColor } from 'seed-to-color'
there's 3 option as you can see, you can use it depends on the chat bubble color, like if the chat bubble is dark use randomLightColor.
Ok, then let's imagine this is the chat
const chats: Chat[] = [
{
_id: 123123,
firstName: "Bambang",
lastName: null,
message: "Good morning guys!",
},
{
_id: 333333,
firstName: "Reza",
lastName: "Aditya",
message: "Morning!",
},
{
_id: 123123,
firstName: "Bambang",
lastName: null,
message: "Good morning Reza!",
},
{
_id: 777777,
firstName: "Andy",
lastName: null,
message: "gm!",
},
{
_id: 887667,
firstName: "Mery",
lastName: null,
message: "Ey good mroningggg!",
},
{
_id: 887667,
firstName: "Mery",
lastName: null,
message: "Morning*",
},
{
_id: 888888,
firstName: "Patrick",
lastName: "Star",
message: "morning guys!",
},
{
_id: 123123,
firstName: "Bambang",
lastName: null,
message: "Morning All!",
},
]
By using the _id we already had the seed to get a unique identifier color, but what I like to do is combine both name and id to get more unique result.
here's the example:
<div className="like twitch">
{chats &&
chats.map((value) => {
const { _id, firstName, lastName, message } = value
const fullName = `${firstName} ${lastName || ""}`.trim()
// because of the library return only hex color without the '#'
// we have to add them manually
// and I'm using randomLightColor for dark background
const color = "#" + randomLightColor(fullName + _id)
return (
<div key={nanoid()} className="chat">
<span style={{ color }}>{fullName}</span>: {message}
</div>
)
})}
</div>
and it will look like this

Pretty simple right?
Now lets do it like telegram. First, I would like to create a functional component for both Profile and bubble
// This component for Profile Image will take the initial name and the color
const IconName = ({ color, initial }: { color: string; initial: string }) => {
return (
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
borderRadius: "100%",
width: "40px",
height: "40px",
backgroundColor: color,
color: '#fff',
fontWeight: 'bold'
}}
>
{initial}
</div>
)
}
and now the bubble
const BubbleMessage = ({
color,
fullName,
message,
}: {
color: string
fullName: string
message: string
}) => {
return (
<div className="bubble">
<div style={{ color }}>{fullName}</div>
<div className="message">{message}</div>
</div>
)
}
And then we can use the component like this:
<div className="like telegram">
{chats &&
chats.map((value) => {
const { _id, firstName, lastName, message } = value
const fullName = `${firstName} ${lastName || ""}`.trim()
const initialName = firstName[0] + (lastName ? lastName[0] : "")
const baseColor = "#" + randomLightColor(_id)
return (
<div key={nanoid()} className="chat">
<IconName color={baseColor} initial={initialName} />
<BubbleMessage
color={baseColor}
fullName={fullName}
message={message}
/>
</div>
)
})}
</div>
Add some css
.chat {
margin-top: 20px;
display: flex;
flex-direction: row;
align-items: flex-end;
}
.bubble {
margin-left: 12px;
background-color: #103b5c;
padding: 10px 15px;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
position: relative;
}
.message {
margin-top: 5px;
}
.bubble::before {
content: "";
position: absolute;
height: 10px;
width: 20px;
bottom: 0;
left: -20px;
border-radius: 0 0 10px 0;
-moz-border-radius: 0 0 10px 0;
-webkit-border-radius: 0 0 10px 0;
-webkit-box-shadow: 10px 0 0 0 #103b5c;
box-shadow: 10px 0 0 0 #103b5c;
}
and you got this look:

Pretty similar right?
You can play along with this using codesandbox
Or fork from the source code on github
Hopefully what I'm writing here is useful for you, subs to my mailing list if you want get notified if I post stuff like this again, Thanks!


