TLTR
Jump to Quick Explanation below to get a 15 second explanation.
Just want to see it in action? Try out the deployed demo. Want a deep dive? Take a peek at the repo.
Requirements
You're required to know the below in order to understand what I'm going to be explaining in this article:
- React Hooks
- React Functional Components
- Styled-Components
Understand the above? Great, keep reading! If you don't I'd do some quick googling to learn about them or for a refresher.
Quick Explanation
This Hook allows the user to create an 'n' number of list items that on hover will emphasize the hovered list item and dim all other elements.
When the user no longer is hovering over a list item all elements will return to the default coleration.
This hook also pairs with a styled component, in this case it's called TextAnimateLi which is hard coded to fit my styling needs but can be changed to your style and element preference.
useTextAnimate
const useTextAnimate = (data) => {
const [content, setContent] = useState(data);
const setOneActive = (name) => {
let contentCopy = [...content];
contentCopy.forEach((item, index, arr) => {
if (arr[index].name !== name) {
arr[index].isActive = false;
}
});
setContent(contentCopy);
};
const setAllActive = () => {
let contentCopy = [...content];
contentCopy.forEach((item, index, arr) => {
arr[index].isActive = true;
});
setContent(contentCopy);
};
return { setOneActive, setAllActive, content };
};
This hook when used takes in an array of objects as it's argument.
const data = useTextAnimate([
{ name: 'work', isActive: true },
{ name: 'about', isActive: true },
]);
From here, we're assigning the array of objects data
to content
in state. This allows us to use stateful logic needed for dynamic style changing.
Then we come onto our first function setOneActive
which will set all elements but the one with the matching name to false. This is the logic that allows us to see one element as emphasized.
The following function setAllActive()
will set all items to be emphasized which is the default logic.
what is returned is:
-
content
- array of objects that the user provided. -
setOneActive
- function -
setAllActive
- function
Real Life use
When using the hook it will take in an array of objects as an argument.
Each object must contain the following properties
- name (Init with the text you want in the list item)
- isActive (set it to true by default always)
const data = useTextAnimate([
{ name: 'work', isActive: true },
{ name: 'about', isActive: true },
{ name: 'contact', isActive: true },
{ name: 'cv', isActive: true },
]);
Note: the value retrieved from useTextAnimate must be assigned to a variable.
useTextContent will return 3 things.
- content (the array of objects from earlier)
- setOneActive (Explained in useTextAnimate above)
- setAllActive (Explained in useTextAnimate above)
The hook provided the logic needed now we are going to populate a unordered list with list items that will use that logic.
Before we start using the logic we are going to need the styled-component TextAnimateLi.
const TextAnimateLi = styled.li`
color: white;
transition: color 0.2s;
cursor: pointer;
${({ content, index }) => {
if (content[index].isActive === false) {
return `
color: rgba(255, 255, 255, 0.5);
`;
}
}}
`;
To keep it short and sweet. It uses data provided by useTextAnimate to style each list item dynamically.
Now in order to put this together, we need to map over the array we created in my example, we can do this with data.content
(Remember, using the variable name data
was a personal choice when creating the variable earlier. It can be anything you'd like!)
<ul className={className}>
{data.content.map((item, index) => {
return (
<TextAnimateLi
key={index}
onMouseEnter={() => data.setOneActive(item.name)}
onMouseLeave={() => data.setAllActive()}
content={data.content}
index={index}
>
{item.name}
</TextAnimateLi>
);
})}
</ul>
What's going on here? The parameter item
in the arrow function is the current object within the array content.
For each Component TextAnimateLi we are adding a set of properties.
key
MUST take index as it's value, do NOT use something like uniqid()).onMouseEnter
Calls the functionsetOneActive()
onMouseLeave
Calls the functionsetAllActive()
content
takes in the array of objectsindex
Takes the current index
Let's take a look back at TextAnimateLi to understand the styling logic.
/* It doesn't have to be a li. But for this case it's the best option. */
const TextAnimateLi = styled.li`
/* This is the default color */
/* You can set a new color here */
color: white;
transition: color 0.2s;
cursor: pointer;
${({ content, index }) => {
if (content[index].isActive === false) {
return `
/* This is the dimming color */
/* You can set a new color here */
color: rgba(255, 255, 255, 0.5);
`;
}
}}
`;
Pretty straight forward, when the current item is not active it will return a color which is dimmed otherwise, it will return to it's default color.
Take a look at my comments in the code to make changes as you see fit. feel free to mess around with the styling for different looks!
Enjoy!
Top comments (0)