Fancy Tooltip customization in React Tooltip component

28 Feb 202524 minutes to read

The arrow of the Tooltip can be customized as needed by customizing CSS on the sample side.

The React Tooltip component is styled using CSS3 and positions the tip arrow according to the Tooltip positions such as TopCenter, BottomLeft, RightTop, and more.

Here, the tip arrow is customized as Curved Tooltip and Bubble tooltip.

Curved tip

The content for the tip pointer arrow has been added. To customize the curved tip arrow, override the following CSS classes of the tip arrow.

 <TooltipComponent content='Tooltip Content' cssClass='curvetips e-tooltip-css'>
    </TooltipComponent>
  .e-arrow-tip-outer.e-tip-bottom,
  .e-arrow-tip-outer.e-tip-top {
        border-left: none !important;
        border-right: none !important;
        border-top: none !important;
  }
  .e-arrow-tip.e-tip-top {
        transform: rotate(170deg);
  }

Bubble tip

The two divs (inner div and outer div) have been added to achieve the bubble tip arrow. To customize the bubble tip arrow, override the following CSS classes of the tip arrow.

  <TooltipComponent content='Tooltip Content' cssClass='bubbletip e-tooltip-css'>
  </TooltipComponent>
    .e-arrow-tip-outer.e-tip-bottom, .e-arrow-tip-outer.e-tip-top
    {
      border-radius: 50px;
      height: 10px;
      width: 10px;
    }

    .e-arrow-tip-inner.e-tip-bottom, .e-arrow-tip-inner.e-tip-top
    {
      border-radius: 50px;
      height: 10px;
      width: 10px;
    }

These tip arrow customizations are achieved through CSS changes at the sample level. The Tooltip position can be changed using the radio button click event.

The arrow tip pointer can also be disabled using the showTipPointer property of the tooltip.

import * as React from 'react';
import { TooltipComponent } from '@syncfusion/ej2-react-popups';
import { ButtonComponent, RadioButtonComponent, } from '@syncfusion/ej2-react-buttons';
function App() {
  let tooltip;
  let bubble;
  function onChange(args) {
    tooltip.position = args.value;
    tooltip.dataBind();
  }
  function onChanged(args) {
    bubble.position = args.value;
    if (bubble.position == "BottomLeft") {
      bubble.offsetY = -30;
    }
    else {
      bubble.offsetY = 0;
    }
    bubble.dataBind();
  }
  return (<div id="container">
    <TooltipComponent cssClass="curvetips e-tooltip-css" content="Tooltip arrow customized" target="#target" ref={d => (tooltip = d)}>
      <TooltipComponent cssClass="bubbletip e-tooltip-css" content="Tooltip arrow customized as balloon tip" target="#bubbletip" position="TopRight" ref={d => (bubble = d)}>
        <TooltipComponent cssClass="pointertip e-tooltip-css" mouseTrail={true} target="#tooltip" content="Disabled Tooltip pointer" showTipPointer={false}>
          <div id="customization" className="customTipContainer">
            <ButtonComponent id="target">Customized Tip Arrow</ButtonComponent>
            <div id="positions">
              <ul>
                <li>
                  <RadioButtonComponent id="element1" label="TopCenter" name="default" checked={true} value="TopCenter" change={onChange} />
                </li>
                <li>
                  <RadioButtonComponent id="element2" label="BottomLeft" name="default" value="BottomLeft" change={onChange} />
                </li>
              </ul>
            </div>
          </div>
          <div id="balloon" className="customTipContainer">
            <ButtonComponent id="bubbletip">Bubble Tip Arrow</ButtonComponent>
            <div id="btn">
              <ul>
                <li>
                  <RadioButtonComponent id="radio1" label="BottomLeft" name="position" value="BottomLeft" change={onChanged} />
                </li>
                <li>
                  <RadioButtonComponent id="radio2" label="TopRight" name="position" value="TopRight" checked={true} change={onChanged} />
                </li>
              </ul>
            </div>
          </div>
          <div id="disabledContainer" className="customTipContainer">
            <ButtonComponent id="tooltip">Disabled Tip Arrow</ButtonComponent>
          </div>
        </TooltipComponent>
      </TooltipComponent>
    </TooltipComponent>
  </div>);
}
export default App;
import * as React from 'react';
import { TooltipComponent } from '@syncfusion/ej2-react-popups';
import {
  ButtonComponent,
  RadioButtonComponent,
  ChangeArgs,
} from '@syncfusion/ej2-react-buttons';

function App() {
  let tooltip: TooltipComponent;
  let bubble: TooltipComponent;

  function onChange(args: ChangeArgs): void {
    tooltip.position = args.value as any;
    tooltip.dataBind();
  }

  function onChanged(args: ChangeArgs): void {
    bubble.position = args.value as any;
    if (bubble.position == "BottomLeft") {
      bubble.offsetY = -30;
    } else {
      bubble.offsetY = 0;
    }
    bubble.dataBind();
  }
  return (
    <div id="container">
      <TooltipComponent
        cssClass="curvetips e-tooltip-css"
        content="Tooltip arrow customized"
        target="#target"
        ref={d => (tooltip = d as any)}
      >
        <TooltipComponent
          cssClass="bubbletip e-tooltip-css"
          content="Tooltip arrow customized as balloon tip"
          target="#bubbletip"
          position="TopRight"
          ref={d => (bubble = d as any)}
        >
          <TooltipComponent
            cssClass="pointertip e-tooltip-css"
            mouseTrail={true}
            target="#tooltip"
            content="Disabled Tooltip pointer"
            showTipPointer={false}
          >
            <div id="customization" className="customTipContainer">
              <ButtonComponent id="target">Customized Tip Arrow</ButtonComponent>
              <div id="positions">
                <ul>
                  <li>
                    <RadioButtonComponent
                      id="element1"
                      label="TopCenter"
                      name="default"
                      checked={true}
                      value="TopCenter"
                      change={onChange as any}
                    />
                  </li>
                  <li>
                    <RadioButtonComponent
                      id="element2"
                      label="BottomLeft"
                      name="default"
                      value="BottomLeft"
                      change={onChange as any}
                    />
                  </li>
                </ul>
              </div>
            </div>
            <div id="balloon" className="customTipContainer">
              <ButtonComponent id="bubbletip">Bubble Tip Arrow</ButtonComponent>
              <div id="btn">
                <ul>
                  <li>
                    <RadioButtonComponent
                      id="radio1"
                      label="BottomLeft"
                      name="position"
                      value="BottomLeft"
                      change={onChanged as any}
                    />
                  </li>
                  <li>
                    <RadioButtonComponent
                      id="radio2"
                      label="TopRight"
                      name="position"
                      value="TopRight"
                      checked={true}
                      change={onChanged as any}
                    />
                  </li>
                </ul>
              </div>
            </div>
            <div id="disabledContainer" className="customTipContainer">
              <ButtonComponent id="tooltip">Disabled Tip Arrow</ButtonComponent>
            </div>
          </TooltipComponent>
        </TooltipComponent>
      </TooltipComponent>
    </div>
  );
}
export default App;
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { TooltipComponent } from '@syncfusion/ej2-react-popups';
import { RadioButtonComponent, } from '@syncfusion/ej2-react-buttons';
function App() {
  let tooltip;
  let bubble;
  function onChange(args) {
    tooltip.position = args.value;
    tooltip.dataBind();
  }
  function onChanged(args) {
    bubble.position = args.value;
    if (bubble.position == 'BottomLeft') {
      bubble.offsetY = -30;
    }
    else {
      bubble.offsetY = 0;
    }
    bubble.dataBind();
  }
  return (<div id="container">
    <TooltipComponent cssClass="curvetips e-tooltip-css" content="Tooltip arrow customized" target="#target" ref={d =>tooltip = d}>
      <TooltipComponent cssClass="bubbletip e-tooltip-css" content="Tooltip arrow customized as balloon tip" target="#bubbletip" position="TopRight" ref={d => bubble = d}>
        <TooltipComponent cssClass="pointertip e-tooltip-css" mouseTrail={true} target="#tooltip" content="Disabled Tooltip pointer" showTipPointer={false}>
          <div id="customization" className="customTipContainer">
            <button className="e-btn" id="target">
              Customized Tip Arrow
            </button>
            <div id="positions">
              <ul>
                <li>
                  <RadioButtonComponent id="element1" label="TopCenter" name="default" checked={true} value="TopCenter" change={onChange} />
                </li>
                <li>
                  <RadioButtonComponent id="element2" label="BottomLeft" name="default" value="BottomLeft" change={onChange} />
                </li>
              </ul>
            </div>
          </div>
          <div id="balloon" className="customTipContainer">
            <button className="e-btn" id="bubbletip">
              Bubble Tip Arrow
            </button>
            <div id="btn">
              <ul>
                <li>
                  <RadioButtonComponent id="radio1" label="BottomLeft" name="position" value="BottomLeft" change={onChanged} />
                </li>
                <li>
                  <RadioButtonComponent id="radio2" label="TopRight" name="position" value="TopRight" checked={true} change={onChanged} />
                </li>
              </ul>
            </div>
          </div>
          <div id="disabledContainer" className="customTipContainer">
            <button className="e-btn" id="tooltip">
              Disabled Tip Arrow
            </button>
          </div>
        </TooltipComponent>
      </TooltipComponent>
    </TooltipComponent>
  </div>);
}
export default App;
ReactDom.render(<App />, document.getElementById('sample'));
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { TooltipComponent } from '@syncfusion/ej2-react-popups';
import {
  RadioButtonComponent,
  ChangeArgs,
} from '@syncfusion/ej2-react-buttons';

function App() {
  let tooltip: TooltipComponent;
  let bubble: TooltipComponent;

  function onChange(args: ChangeArgs): void {
    tooltip.position = args.value as any;
    tooltip.dataBind();
  }

  function onChanged(args: ChangeArgs): void {
    bubble.position = args.value as any;
    if (bubble.position == 'BottomLeft') {
      bubble.offsetY = -30;
    } else {
      bubble.offsetY = 0;
    }
    bubble.dataBind();
  }
  return (
    <div id="container">
      <TooltipComponent
        cssClass="curvetips e-tooltip-css"
        content="Tooltip arrow customized"
        target="#target"
        ref={d =>tooltip = d}
      >
        <TooltipComponent
          cssClass="bubbletip e-tooltip-css"
          content="Tooltip arrow customized as balloon tip"
          target="#bubbletip"
          position="TopRight"
          ref={d => bubble = d}
        >
          <TooltipComponent
            cssClass="pointertip e-tooltip-css"
            mouseTrail={true}
            target="#tooltip"
            content="Disabled Tooltip pointer"
            showTipPointer={false}
          >
            <div id="customization" className="customTipContainer">
              <button className="e-btn" id="target">
                Customized Tip Arrow
              </button>
              <div id="positions">
                <ul>
                  <li>
                    <RadioButtonComponent
                      id="element1"
                      label="TopCenter"
                      name="default"
                      checked={true}
                      value="TopCenter"
                      change={onChange}
                    />
                  </li>
                  <li>
                    <RadioButtonComponent
                      id="element2"
                      label="BottomLeft"
                      name="default"
                      value="BottomLeft"
                      change={onChange}
                    />
                  </li>
                </ul>
              </div>
            </div>
            <div id="balloon" className="customTipContainer">
              <button className="e-btn" id="bubbletip">
                Bubble Tip Arrow
              </button>
              <div id="btn">
                <ul>
                  <li>
                    <RadioButtonComponent
                      id="radio1"
                      label="BottomLeft"
                      name="position"
                      value="BottomLeft"
                      change={onChanged}
                    />
                  </li>
                  <li>
                    <RadioButtonComponent
                      id="radio2"
                      label="TopRight"
                      name="position"
                      value="TopRight"
                      checked={true}
                      change={onChanged}
                    />
                  </li>
                </ul>
              </div>
            </div>
            <div id="disabledContainer" className="customTipContainer">
              <button className="e-btn" id="tooltip">
                Disabled Tip Arrow
              </button>
            </div>
          </TooltipComponent>
        </TooltipComponent>
      </TooltipComponent>
    </div>
  );
}
export default App;
ReactDom.render(<App />, document.getElementById('sample'));
#loader {
  color: #008cff;
  height: 40px;
  left: 45%;
  position: absolute;
  top: 45%;
  width: 30%;
}

#bubbletip {
  border-color: #d2a679;
}

#target {
  border-color: #e86238;
}

li {
  list-style: none;
}

.e-radio-wrapper {
  margin-top: 18px;
}

#target,
#bubbletip,
#tooltip {
  box-sizing: border-box;
  padding: 20px;
  width: 200px;
  text-align: center;
  top: -17px;
  margin-bottom: 40px;
}

/* csslint ignore:start */

@font-face {
  font-family: "tip";
  src: url("https://ej2.syncfusion.com/products/typescript/tooltip/customization/Fonts/tip.tff") format("truetype"), url("https://ej2.syncfusion.com/products/typescript/tooltip/customization/Fonts/tip.woff") format("woff"), url("https://ej2.syncfusion.com/products/typescript/tooltip/customization/Fonts/tip.eot") format("eot"), url("https://ej2.syncfusion.com/products/typescript/tooltip/customization/Fonts/tip.svg?#tip") format("svg");
  font-weight: normal;
  font-style: normal;
}

/* csslint ignore:end */

/* csslint ignore:start */

#container {
  width: 100%;
}

.customTipContainer {
  width: 400px;
  position: relative;
  left: 50%;
  transform: translateX(-50%);
  top: 70px;
}

#disabledContainer {
  margin-top: 25px;
}

.pointertip.e-tooltip-wrap .e-tip-content,
.curvetips.e-tooltip-wrap .e-tip-content {
  color: white;
}

.pointertip.e-tooltip-wrap.e-popup {
  background-color: #80180d;
  border: 3px solid #ff9999;
}

.curvetips .e-arrow-tip.e-tip-top {
  margin-left: -20px;
  top: -16px;
  transform: rotate(177deg);
  left: 50px;
}

.curvetips.e-tooltip-wrap {
  padding: 17px;
  border-radius: 5px;
}

.curvetips.e-tooltip-wrap .e-arrow-tip-outer.e-tip-bottom:before,
.curvetips.e-tooltip-wrap .e-arrow-tip-outer.e-tip-top:before {
  font-family: "tip" !important;
  speak-as: none;
  font-size: 21px;
  font-style: normal;
  font-weight: normal;
  font-variant: normal;
  text-transform: none;
  line-height: 1;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  content: "\e700";
  color: #e86238;
}

.curvetips.e-tooltip-wrap.e-popup {
  background: #e86238;
  border: none;
}

.curvetips.e-tooltip-wrap .e-arrow-tip-outer.e-tip-bottom,
.curvetips.e-tooltip-wrap .e-arrow-tip-outer.e-tip-top {
  border-left: none;
  border-right: none;
  border-top: none;
}

.curvetips.e-tooltip-wrap .e-arrow-tip-inner.e-tip-bottom:before,
.curvetips.e-tooltip-wrap .e-arrow-tip-inner.e-tip-top:before {
  content: none;
}

.curvetips.e-tooltip-wrap .e-arrow-tip-outer.e-tip-bottom,
.curvetips.e-tooltip-wrap .e-arrow-tip-outer.e-tip-top {
  top: -1px;
}

.curvetips.e-tooltip-wrap .e-arrow-tip.e-tip-bottom,
.curvetips.e-tooltip-wrap .e-arrow-tip.e-tip-top {
  position: absolute;
  height: 18px;
  width: 28px;
}

#positions,
#btn {
  display: inline-block;
}

#target .e-tip-content {
  padding: 0px;
}

.bubbletip.e-tooltip-wrap {
  padding: 8px;
}

.bubbletip.e-tooltip-wrap .e-tip-content {
  border-radius: 50%;
  text-align: center;
  color: white;
}

.bubbletip.e-tooltip-wrap .e-arrow-tip.e-tip-bottom {
  height: 40px;
  width: 50px;
}

.bubbletip.e-tooltip-wrap .e-arrow-tip.e-tip-top {
  height: 40px;
  width: 40px;
}

.bubbletip.e-tooltip-wrap .e-arrow-tip.e-tip-left,
.bubbletip.e-tooltip-wrap .e-arrow-tip.e-tip-right {
  height: 12px;
  width: 20px;
}


.bubbletip.e-tooltip-wrap.e-popup {
  border: 5px solid #dfccad;
  background-color: #7b5e32;
}

.bubbletip.e-tooltip-wrap .e-arrow-tip-outer.e-tip-bottom {
  height: 10px;
  width: 10px;
  border: 1px solid #dfccad;
  background-color: #7b5e32;
  border-radius: 50px;
  margin-top: 20px;
  margin-right: 20px;
}

.e-arrow-tip.e-tip-top {
  margin-left: 60px;
}

.bubbletip.e-tooltip-wrap .e-arrow-tip-outer.e-tip-top {
  border: 1px solid #dfccad;
  border-radius: 50px;
  background-color: #7b5e32;
  width: 10px;
  height: 10px;
  margin-left: 20px;
}

.bubbletip.e-tooltip-wrap .e-arrow-tip-outer.e-tip-left {
  border-bottom: 6px solid transparent;
  border-right: 20px solid #dfccad;
  border-top: 6px solid transparent;
}

.bubbletip.e-tooltip-wrap .e-arrow-tip-outer.e-tip-right {
  border-bottom: 6px solid transparent;
  border-left: 20px solid #dfccad;
  border-top: 6px solid transparent;
}

.bubbletip.e-tooltip-wrap .e-arrow-tip-inner.e-tip-bottom {
  margin-top: -2px;
  margin-left: 8px;
  content: none;
  top: 1px !important;
  border: 2px solid #dfccad;
  width: 20px;
  height: 20px;
  border-radius: 50px;
  background-color: #7b5e32;
}

.bubbletip .e-arrow-tip.e-tip-top {
  left: 44px !important;
  top: -19px !important;
}

.bubbletip .e-arrow-tip.e-tip-bottom {
  top: 88.9% !important;
  left: 4px !important;
}

.bubbletip.e-tooltip-wrap .e-arrow-tip-inner.e-tip-top {
  top: 10px !important;
  border: 2px solid #dfccad;
  width: 20px;
  height: 20px;
  border-radius: 50px;
  background-color: #7b5e32;
}

.bubbletip.e-tooltip-wrap .e-arrow-tip-inner.e-tip-top:before {
  content: None;
}

.bubbletip.e-tooltip-wrap .e-tip-content {
  border-radius: inherit;
}

.bubbletip.e-tooltip-wrap.bubbletip {
  width: 150px !important;
  border-radius: 50%;
}

/* csslint ignore:end */
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Syncfusion React Tooltip</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Essential JS 2 for React Components" />
    <meta name="author" content="Syncfusion" />
    <link href="https://cdn.syncfusion.com/ej2/29.1.33/ej2-base/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/29.1.33/ej2-react-popups/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/29.1.33/ej2-react-buttons/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/29.1.33/ej2-inputs/styles/material.css" rel="stylesheet" />
    <link href="index.css" rel="stylesheet" />
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</head>

<body>
    <div id='sample'>
        <div id='loader'>Loading....</div>
    </div>
</body>

</html>