Building CampaignHawk: Connecting Tooltips with React (Part 5)
The tooltips are now properly styled but are not connected. Connecting things takes a lot longer in React than I’m used to with Blaze, but as Nick Wientge put it:
React can be very frustrating at first because it literally forces you to do things the “right” way. However, anytime I hit a wall with React I later realized it was because I was trying to do something that would have gotten me in trouble later.
I happen to agree with this sentiment, and the bigger my projects get, I find they are much more easily maintained when I use React.
Now is a good time to give some thought to the functions we need to pass down to the child components. SidenavTooltip will need to know the x and y position of the cursor on hover and whether or not the tooltip should be visible. SidenavIcons will need to know when each item is being hovered-over to tell the parent component to show the tooltip.
<SidenavTooltip
showTooltip={this.state.showTooltip}
tooltipX={this.state.tooltipX}
tooltipY={this.state.tooltipY}/>
In the component above, we’re passing the x and y position of tooltipX and tooltipY to tell our SidenavTooltip where to go. In the SidenavIcons component below, we’re passing two functions to change the state of showTooltip to either true or false based on whether an icon is being hovered over or not.
<SidenavIcons
showTooltip={this.showTooltip}
hideToolip={this.hideTooltip} />
First let’s go into SidenavTooltip and set the inline style we talked about earlier:
tooltipStyle = {
top: this.props.tooltipY,
left: this.props.tooltipX
}
Then we need to change the opacity based on the status of showTooltip:
if (this.props.showTooltip) {
tooltipStyle.opacity = "1";
tooltipStyle.visibility = "visible";
} else {
tooltipStyle.opacity = "0";
tooltipStyle.visibility = "hidden";
}
We’re not quite done with tooltips. We need to change the content of the tooltip based on the icon being hovered over. To do this, we’ll have to change our icons into objects with a name and a description. For the sake of space, I’m not going to fill out all items. You should get an idea from the example below:
let iconList = [
{name: "fa fa-database", description: "Data Layers"},
...
You’ll also have to change the key and className to item.name in your map function.
In Sidenav, add a new initial state called tooltipDescription:
...
tooltipDescription: "",
...
And since Sidenav is the component that ultimately handles the name of the tooltip, we need to create a new function to set tooltipDescription:
setTooltipDescription(item) {
this.setState({
tooltipDescription: item.description
})
},
We also need to pass the value of tooltipDescription into SidenavTooltip and pass the setTooltipDescription function into SidenavIcons.
<SidenavTooltip
tooltipDescription={this.state.tooltipDescription}
...
…And:
<SidenavIcons
setTooltipDescription={this.setTooltipDescription}
...
Then we want to add an onMouseEnter event in our SidenavIcons to bind to item so we can set tooltipDescription, an onMouseOver event to keep the tooltip showing while the mouse is over the icon, and an onMouseOut event to stop it from showing.
<li key={item.name}
onMouseEnter={this.props.setTooltipDescription.bind(null, item)}
onMouseOver={this.props.showTooltip}
onMouseOut={this.props.hideTooltip}
...
And the last thing we need to do to finish the tooltips is set the tooltipDescription in the SidenavTooltip component using this.props.tooltipDescription that we passed in from Sidenav.
<div className="sidenav-tooltip" style={tooltipStyle}>
<p>{this.props.tooltipDescription}</p>
The last thing to change is the width of the tooltip box.
First remove the width property from sidenav-tooltip. This is just another CSS property that we need to add to our paragraph tag .
p {
color: $default-text-color;
white-space: nowrap;
font-size: 1.5em;
padding: 10px;
align-self: center;
}
At this point, the app looks like the example below. There is no map and no real functionality. Just a nice sidenav with icons and tooltips.
Next Steps
Now that our tooltips behave properly, we need to build some modals. Most of the tools in our sidenav will trigger a modal, so we need to make sure they’re decent.
Sam Corcos is the lead developer and co-founder of Sightline Maps, the most intuitive platform for 3D printing topographical maps, as well as LearnPhoenix.io, an advanced tutorial site for building scaleable production apps with Phoenix and React.
Cumulative Time
Additional
- Building CampaignHawk: An open-source election canvassing app with Meteor and React (Part 1)
- File Structure and Packages (Part 2)
- Styling the Sidenav (Part 3)
- Styling Tooltips (Part 4)
- Connecting Tooltips with React (Part 5)
- Making Modals (Part 6)
- Populating Modals (Part 7)
- Connecting Modals with React (Part 8)
- Mapbox and Data (Part 9)
- Thinking about Data (Part 10)
- Mapbox and GeoJSON (Part 11)
- Mapbox.js and Meteor Data (Part 12)
- Popouts and Radio Buttons (Part 13)
- Radio Button Styling (Part 14)
- Triggering Functions with Radio Buttons (Part 15)
- Spacial Analysis Overview (Part 16)
- Clustering with Leaflet Markercluster (Part 17)
- Making a Precinct Data Layer (Part 18)
- Scaling Colors and Values with D3 (Part 19)
- Styling the Precinct Data Layer (Part 20)
- Toggling Data Layers (Part 21)
- Voter Filter Data Layer (Part 22)