Styling a “react-mentions” Component With JSS
Implementing the Material-UI look & feel from scratch using the “makeStyles” API
Intro
Recently we, at SundaySky, wanted to add a new feature with which the user can input text, and when typing a specific character, a list of suggestions pops up. The user can then select an item from the list and have a visual indication of the selected item in the input field.
As you can see, this experience is very similar to what we see in platforms like Facebook / Twitter / Medium in which we can mention people using the “@” sign.
This feature is commonly called “mention”.
Research
The first step towards this new feature was research — are there any existing solutions out there that can fit our requirements?
So while searching around the web, I came across this wonderful article which describes how to implement mentions using the react-mentions
library.
Nice! What a great start. Thanks Ganesh Ravi Shankar!
So, I made a small POC of a mention component using react-mentions
and our product team approved that it met our functional requirements.
Next up — styling!
Piece of cake, right?
Not quite…
The Challenges
At SundaySky we manage our core UI components in a separate repository, called “Component Library”. In this library we define the look & feel (colors, fonts, animations, dark/light theme support, etc.) of all the components, resulting in reusable components with a consistent streamlined UX across our applications.
Challenge #1
Our design system is based entirely on Material-UI. So the UX guideline was that the new component should have the same look & feel as Material-UI Autocomplete.
See the following GIF for example. Notice how the placeholder text (e.g., “Mui Autocomplete”) decreases in size and moves out of the way when the component gains focus.
This is an example of out-of-the-box Material-UI behavior that needed to be implemented since react-mentions
offers zero out-of-the-box styling.
So basically, I had to replicate the Material-UI style from scratch.
Challenge #2
We use theming to style the components in our component library.
Theme is a global object that defines all of the styling properties of the application, such as color palette, transitions, typography, spacing etc.
See this theme object for example.
The main benefit of theming is that all of the styling properties are defined in one place, usually located at the root of the application, and can be used anywhere in the application without having to rewrite “hard-coded” styles all over the place.
In our component library, we use the Material-UI makeStyles
API for theming (JSS syntax). As we’ll see in the following chapter, styling a react-mentions
component is not trivial and all of the sources I found on the web used CSS for that, while I needed to do it with JSS.
Let’s Get Down to Business
Part 1 — styling the “react-mentions” elements
As Ganesh’s article states, we can apply a custom style to every element within react-mentions
by overriding specific className
attributes (yeah, it’s weird but it works).
For example, given the following component…
…this is the rendered DOM when the suggestion list is open:
We see that we can override the following className
attributes to style their matching elements:
ssky-mention-input__control
: root control elementssky-mention-input__highlighter
: highlighter elementssky-mention-input__input
: input elementssky-mention-input__suggestions
: suggestion list wrapperssky-mention-input__suggestions__list
: suggestion listssky-mention-input__suggestions__item
: suggestion list itemssky-mention-input__suggestions__item--focused
: focused suggestion list item
Since I was adding this component to our component library, it needed to be generic and reusable as possible, and still have a default style. This styling method forced me to have a fixed className
for the <MentionsInput />
component, which is not ideal in terms of genericity.
This is how the className
override is done using the makeStyles
API:
Part 2 — styling the highlighted mentions
Styling the highlighted mention can be done only by passing the style
prop to the <Mention />
component. This is my style
object:
Part 3 — styling the input placeholder
The placeholder (a.k.a., “floating label”) was tricky because I had to carefully place it inside the input field and understand when to style it as a superscript and when not to. It should be superscript if the input field is focused or if it contains a value.
This is how the placeholder styling is done using the makeStyles
API:
Final Result
After days of learning and experimenting with react-mentions
, CSS, JSS, Material-UI APIs and all in between… this is the final result:
And the full code…
defaultStyles.ts
:
SskyMentionInput.tsx
:
That’s it. Thank you for reading! 🙏
Good luck!