Skip to content

Tooltips

There are two ways of implementing tooltips - with state management or with css.

Code for the example above

import { GanttChart } from "@gantt-insights/gi-gantt-react";
import { useState } from "react";
import { usePointerHover } from "./util/usePointerHover";
export function Example() {
return (
// eslint-disable-next-line tailwindcss/no-custom-classname
<div className="not-content" style={{ height: 300 }}>
<GanttChart
data={[
{
id: "1",
fields: {
id: () => <>1</>,
},
activities: [
{
id: "1-1",
from: new Date(2024, 1, 3),
to: new Date(2024, 1, 12),
renderElement: () => {
const [tooltipVisisble, setTooltipVisisble] = useState(false);
return (
<div
className="size-full"
onMouseEnter={() => setTooltipVisisble(true)}
onMouseLeave={() => setTooltipVisisble(false)}
>
<div className="flex size-full items-center justify-center bg-sky-800">
State management tooltip
</div>
{tooltipVisisble && (
<div className="absolute left-0 top-6 rounded-md bg-slate-800 p-1">
This is a absolute hover offset from the top
</div>
)}
</div>
);
},
},
],
},
{
id: "2",
fields: {
id: () => <>2</>,
},
activities: [
{
id: "2-1",
from: new Date(2024, 1, 3),
to: new Date(2024, 1, 12),
renderElement: () => {
const tooltipHeight = 120;
const tooltipWidth = 200;
const { onMouseEnter, rootDivRef, tooltipPosition } =
usePointerHover({
approxHeight: tooltipHeight,
approxWidth: tooltipWidth,
});
return (
<div
className="group size-full"
onMouseEnter={onMouseEnter}
ref={rootDivRef}
>
<div className="flex size-full items-center justify-center bg-sky-800">
CSS tooltip
</div>
<div
className="fixed hidden rounded-md bg-slate-800 p-1 group-hover:flex"
style={{
top: tooltipPosition.top,
left: tooltipPosition.left,
height: tooltipHeight,
width: tooltipWidth,
}}
>
This is mouse hover with fixed position based on pointer
location
</div>
</div>
);
},
},
],
},
]}
columns={[
{
id: "id",
renderElement: () => <>ID</>,
width: 50,
},
]}
links={[]}
timeframes={[]}
markers={[]}
zoomLevel={14}
chartStyle={{
tableHeaderBackgroundColor: "var(--sl-color-bg-nav)",
tableHeaderBorderSize: [1, 0, 1, 0],
tableHeaderBorderColor: "var(--sl-color-hairline-light)",
tableRowBackgroundColor: "transparent",
tableRowHighlightColor: "rgba(0,0,0,0.1)",
tableRowBorderSize: [1, 0, 1, 0],
tableRowBorderColor: "var(--sl-color-bg-nav)",
timelineHeaderBackgroundColor: "var(--sl-color-bg-sidebar)",
timelineHeaderHighlightColor: "rgba(0,0,0,0.1)",
timelineHeaderBorderSize: 1,
timelineHeaderBorderColor: "var(--sl-color-hairline-light)",
timelineActivityBackgroundColor: "transparent",
timelineActivityHighlightColor: "rgba(0,0,0,0.1)",
timelineActivityBorderSize: 1,
timelineActivityBorderColor: "transparent",
tableResizerColor: "transparent",
tableResizerActiveColor: "var(--sl-color-text-invert)",
tableResizerHoverColor: "var(--sl-color-text-accent)",
tableResizerWidth: 2,
fieldResizerColor: "transparent",
fieldResizerActiveColor: "var(--sl-color-text-invert)",
fieldResizerHoverColor: "var(--sl-color-text-accent)",
fieldResizerWidth: 2,
linkColor: "var(--sl-color-text-accent)",
linkWidth: 3,
rowHeight: 30,
}}
dateTimeframeRenderElements={{
day: (_year, _monthIndex, day) => () => <>{day}</>,
month: (year, monthIndex) => () => (
<>
{year}-{monthIndex + 1}
</>
),
}}
tableContainerWidth={55}
/>
</div>
);
}

The mouse pointer hover is done by this utility hook

import { useCallback, useRef, useState } from "react";
type Args = {
approxWidth: number;
approxHeight: number;
};
type Return = {
tooltipPosition: { top: number; left: number };
rootDivRef: React.RefObject<HTMLDivElement>;
onMouseEnter: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
};
export const usePointerHover = ({
approxHeight,
approxWidth,
}: Args): Return => {
const [tooltipPosition, setTooltipPosition] = useState({ top: 0, left: 0 });
const rootDivRef = useRef<HTMLDivElement>(null);
const onMouseEnter = useCallback(
(event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
const isOutOfViewportDown =
approxHeight + event.clientY > window.innerHeight;
const isOutOfViewportRight =
approxWidth + event.clientX > window.innerWidth;
setTooltipPosition({
top: isOutOfViewportDown ? event.clientY - approxHeight : event.clientY,
left: isOutOfViewportRight
? event.clientX - approxWidth
: event.clientX,
});
},
[approxHeight, approxWidth],
);
return {
tooltipPosition,
rootDivRef,
onMouseEnter,
};
};