diff --git a/docs/docs/examples/styling.mdx b/docs/docs/examples/styling.mdx
index ebce197f..724e479f 100644
--- a/docs/docs/examples/styling.mdx
+++ b/docs/docs/examples/styling.mdx
@@ -106,10 +106,14 @@ import { Tooltip } from 'react-tooltip'
Please note that **Core** styles are different from **Base** styles, for more information, please check the [Disabling ReactTooltip CSS](#disabling-reacttooltip-css) section.
:::
+##### Base styles
+
In this example, we are adding an extra level to the CSS classes. The following are the default **base** styles for the tooltip:
{TooltipStyles}
+##### Core styles
+
And the following are the **core** styles for the tooltip:
{TooltipCoreStyles}
@@ -370,35 +374,51 @@ In summary, if you do it correctly you can use CSS specificity instead of `!impo
### Disabling ReactTooltip CSS
-There are two ways to remove the ReactTooltip CSS:
+ReactTooltip works seamlessly by automatically injecting CSS into your application. To disable this functionality, use the tooltip prop `disableStyleInjection`.
+Details on how it works:
+
+- Set to `true`: what we call "base" styles will be disabled. Useful if you wish to style your tooltip from scratch.
+- Set to `'core'`: both the "base" and the "core" styles will be disabled. This means the tooltip will not work properly without adding specific CSS attributes to it.
+
+In both cases, you can add `import 'react-tooltip/dist/react-tooltip.css'` to your project to get the tooltip working again, or add your own custom CSS.
-#### Environment Variables
+:::caution
-You can prevent ReactTooltip from injecting styles into the page by using environment variables, we currently support two types of styles: `core styles` and `base styles`.
+Do not set `disableStyleInjection` dynamically. Changing its value requires a page refresh, so that will not work.
-- Core Styles: basic styles that are necessary to make the tooltip work.
-- Base Styles: visual styles to make the tooltip pretty.
+:::
:::info
-We strongly recommend using this way because it's cleaner and better for performance to choose not to inject the styles instead of injecting and removing them when the page loads.
+Check out more details about the [base](#base-styles) and [core](#core-styles) styles.
:::
+#### Environment variables
+
+:::danger
+
+This has been deprecated. Use [`disableStyleInjection`](#disabling-reacttooltip-css) instead.
+
+:::
+
+You can prevent ReactTooltip from injecting styles into the page by using environment variables.
+
| name | type | required | default | values | description |
| ----------------------------------- | --------- | -------- | ------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `REACT_TOOLTIP_DISABLE_CORE_STYLES` | `boolean` | no | `false` | `true` `false` | Environment variable to disable **core** styles from being injected into the page by ReactTooltip.
We strongly recommend to keep the core styles being injected into the project unless you know what you are doing. |
| `REACT_TOOLTIP_DISABLE_BASE_STYLES` | `boolean` | no | `false` | `true` `false` | Environment variable to disable **base** styles from being injected into the page by ReactTooltip.
Those styles are just visual styles like colors, padding, etc... And can be disabled if you want to write your tooltip styles. |
-#### Using removeStyle function
-:::caution
+#### `removeStyle()` function
+
+:::danger
-Only use this method if you really can't use the environment variables to disable the style injection of ReactTooltip because this can impact the page performance.
+This has been deprecated. Use [`disableStyleInjection`](#disabling-reacttooltip-css) instead.
:::
-The function `removeStyle` accepts the following params:
+You can also use the `removeStyle()` function to remove injected styles from the page. It accepts the following parameters:
| name | type | required | default | values | description |
| ---- | ------ | -------- | ------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
@@ -407,8 +427,6 @@ The function `removeStyle` accepts the following params:
```jsx
import { removeStyle } from 'react-tooltip'
-...
-
removeStyle() // removes the injected base style of ReactTooltip
removeStyle({ type: 'core' }) // removes the injected core style of ReactTooltip - this can affect the basic functionality of ReactTooltip
```
diff --git a/docs/docs/options.mdx b/docs/docs/options.mdx
index 0e749f9f..4cf2e3e1 100644
--- a/docs/docs/options.mdx
+++ b/docs/docs/options.mdx
@@ -87,50 +87,40 @@ import { Tooltip } from 'react-tooltip';
#### Available props
-| name | type | required | default | values | description |
-| ------------------ | -------------------------- | -------- | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `className` | `string` | no | | | Class name to customize tooltip element. You can also use the default class `react-tooltip` which is set internally |
-| `classNameArrow` | `string` | no | | | Class name to customize tooltip arrow element. You can also use the default class `react-tooltip-arrow` which is set internally |
-| `content` | `string` | no | | | Content to de displayed in tooltip (`html` prop is priorized over `content`) |
-| ~~`html`~~ | ~~`string`~~ | ~~no~~ | | | ~~HTML content to de displayed in tooltip~~
**DEPRECATED**
Use `children` or `render` instead |
-| `render` | `function` | no | | | A function which receives a ref to the currently active anchor element and returns the content for the tooltip. Check the [examples](./examples/render.mdx) |
-| `place` | `string` | no | `top` | `top` `top-start` `top-end` `right` `right-start` `right-end` `bottom` `bottom-start` `bottom-end` `left` `left-start` `left-end` | Position relative to the anchor element where the tooltip will be rendered (if possible) |
-| `offset` | `number` | no | `10` | any `number` | Space between the tooltip element and anchor element (arrow not included in calculation) |
-| `id` | `string` | no | | any `string` | The tooltip id. Must be set when using `data-tooltip-id` on the anchor element |
-| ~~`anchorId`~~ | ~~`string`~~ | ~~no~~ | | ~~any `string`~~ | ~~The id for the anchor element for the tooltip~~
**DEPRECATED**
Use `data-tooltip-id` or `anchorSelect` instead |
-| `anchorSelect` | CSS selector | no | | any valid CSS selector | The selector for the anchor elements. Check [the examples](./examples/anchor-select.mdx) for more details |
-| `variant` | `string` | no | `dark` | `dark` `light` `success` `warning` `error` `info` | Change the tooltip style with default presets |
-| `wrapper` | HTML tag | no | `div` | `div` `span` `p` ... | Element wrapper for the tooltip container, can be `div`, `span`, `p` or any valid HTML tag |
-| `children` | React node | no | `undefined` | valid React children | The tooltip children have lower priority compared to the `content` prop and the `data-tooltip-content` attribute. Useful for setting default content |
-| ~~`events`~~ | ~~`string[]`~~ | ~~no~~ | ~~`hover`~~ | ~~`hover` `click`~~ | ~~Events to watch for when handling the tooltip state~~
**DEPRECATED**
Use `openOnClick` tooltip prop instead |
-| `openOnClick` | `boolean` | no | `false` | `true` `false` | Controls whether the tooltip should open when clicking (`true`) or hovering (`false`) the anchor element |
-| `positionStrategy` | `string` | no | `absolute` | `absolute` `fixed` | The position strategy used for the tooltip. Set to `fixed` if you run into issues with `overflow: hidden` on the tooltip parent container |
-| `delayShow` | `number` | no | | any `number` | The delay (in ms) before showing the tooltip |
-| `delayHide` | `number` | no | | any `number` | The delay (in ms) before hiding the tooltip |
-| `float` | `boolean` | no | `false` | `true` `false` | Tooltip will follow the mouse position when it moves inside the anchor element (same as V4's `effect="float"`) |
-| `hidden` | `boolean` | no | `false` | `true` `false` | Tooltip will not be shown |
-| `noArrow` | `boolean` | no | `false` | `true` `false` | Tooltip arrow will not be shown |
-| `clickable` | `boolean` | no | `false` | `true` `false` | Allow interaction with elements inside the tooltip. Useful when using buttons and inputs |
-| `closeOnEsc` | `boolean` | no | `false` | `true` `false` | Pressing escape key will close the tooltip |
-| `closeOnScroll` | `boolean` | no | `false` | `true` `false` | Scrolling will close the tooltip (for this to work, scroll element must be either the root html tag, the tooltip parent, or the anchor parent) |
-| `closeOnResize` | `boolean` | no | `false` | `true` `false` | Resizing the window will close the tooltip |
-| `style` | `CSSProperties` | no | | a CSS style object | Add inline styles directly to the tooltip |
-| `position` | `{ x: number; y: number }` | no | | any `number` value for both `x` and `y` | Override the tooltip position on the DOM |
-| `isOpen` | `boolean` | no | handled by internal state | `true` `false` | The tooltip can be controlled or uncontrolled, this attribute can be used to handle show and hide tooltip outside tooltip (can be used **without** `setIsOpen`) |
-| `setIsOpen` | `function` | no | | | The tooltip can be controlled or uncontrolled, this attribute can be used to handle show and hide tooltip outside tooltip |
-| `afterShow` | `function` | no | | | A function to be called after the tooltip is shown |
-| `afterHide` | `function` | no | | | A function to be called after the tooltip is hidden |
-| `middlewares` | `Middleware[]` | no | | array of valid `floating-ui` middlewares | Allows for advanced customization. Check the [`floating-ui` docs](https://floating-ui.com/docs/middleware) for more information |
-| `border` | `CSSProperties['border']` | no | | a CSS border style | Change the style of the tooltip border (including the arrow) |
-| `opacity` | `CSSProperties['opacity']` | no | `0.9` | a CSS opacity value | Change the opacity of the tooltip |
-
-### Envs
-
-We have some environment variables that can be used to enable or disable some behavior of the ReactTooltip, normally used on the server side.
-
-#### Available environment variables:
-
-| name | type | required | default | values | description |
-| ----------------------------------- | --------- | -------- | ------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `REACT_TOOLTIP_DISABLE_CORE_STYLES` | `boolean` | no | `false` | `true` `false` | Environment variable to disable **core** styles from being injected into the page by ReactTooltip.
We strongly recommend to keep the core styles being injected into the project unless you know what you are doing. |
-| `REACT_TOOLTIP_DISABLE_BASE_STYLES` | `boolean` | no | `false` | `true` `false` | Environment variable to disable **base** styles from being injected into the page by ReactTooltip.
Those styles are just visual styles like colors, padding, etc... And can be disabled if you want to write your tooltip styles. |
+| name | type | required | default | values | description |
+| ----------------------- | -------------------------------------- | -------- | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `className` | `string` | no | | | Class name to customize tooltip element. You can also use the default class `react-tooltip` which is set internally |
+| `classNameArrow` | `string` | no | | | Class name to customize tooltip arrow element. You can also use the default class `react-tooltip-arrow` which is set internally |
+| `content` | `string` | no | | | Content to de displayed in tooltip (`html` prop is priorized over `content`) |
+| ~~`html`~~ | ~~`string`~~ | ~~no~~ | | | ~~HTML content to de displayed in tooltip~~
**DEPRECATED**
Use `children` or `render` instead |
+| `render` | `function` | no | | | A function which receives a ref to the currently active anchor element and returns the content for the tooltip. Check the [examples](./examples/render.mdx) |
+| `place` | `string` | no | `top` | `top` `top-start` `top-end` `right` `right-start` `right-end` `bottom` `bottom-start` `bottom-end` `left` `left-start` `left-end` | Position relative to the anchor element where the tooltip will be rendered (if possible) |
+| `offset` | `number` | no | `10` | any `number` | Space between the tooltip element and anchor element (arrow not included in calculation) |
+| `id` | `string` | no | | any `string` | The tooltip id. Must be set when using `data-tooltip-id` on the anchor element |
+| ~~`anchorId`~~ | ~~`string`~~ | ~~no~~ | | ~~any `string`~~ | ~~The id for the anchor element for the tooltip~~
**DEPRECATED**
Use `data-tooltip-id` or `anchorSelect` instead |
+| `anchorSelect` | CSS selector | no | | any valid CSS selector | The selector for the anchor elements. Check [the examples](./examples/anchor-select.mdx) for more details |
+| `variant` | `string` | no | `dark` | `dark` `light` `success` `warning` `error` `info` | Change the tooltip style with default presets |
+| `wrapper` | HTML tag | no | `div` | `div` `span` `p` ... | Element wrapper for the tooltip container, can be `div`, `span`, `p` or any valid HTML tag |
+| `children` | React node | no | `undefined` | valid React children | The tooltip children have lower priority compared to the `content` prop and the `data-tooltip-content` attribute. Useful for setting default content |
+| ~~`events`~~ | ~~`string[]`~~ | ~~no~~ | ~~`hover`~~ | ~~`hover` `click`~~ | ~~Events to watch for when handling the tooltip state~~
**DEPRECATED**
Use `openOnClick` tooltip prop instead |
+| `openOnClick` | `boolean` | no | `false` | `true` `false` | Controls whether the tooltip should open when clicking (`true`) or hovering (`false`) the anchor element |
+| `positionStrategy` | `string` | no | `absolute` | `absolute` `fixed` | The position strategy used for the tooltip. Set to `fixed` if you run into issues with `overflow: hidden` on the tooltip parent container |
+| `delayShow` | `number` | no | | any `number` | The delay (in ms) before showing the tooltip |
+| `delayHide` | `number` | no | | any `number` | The delay (in ms) before hiding the tooltip |
+| `float` | `boolean` | no | `false` | `true` `false` | Tooltip will follow the mouse position when it moves inside the anchor element (same as V4's `effect="float"`) |
+| `hidden` | `boolean` | no | `false` | `true` `false` | Tooltip will not be shown |
+| `noArrow` | `boolean` | no | `false` | `true` `false` | Tooltip arrow will not be shown |
+| `clickable` | `boolean` | no | `false` | `true` `false` | Allow interaction with elements inside the tooltip. Useful when using buttons and inputs |
+| `closeOnEsc` | `boolean` | no | `false` | `true` `false` | Pressing escape key will close the tooltip |
+| `closeOnScroll` | `boolean` | no | `false` | `true` `false` | Scrolling will close the tooltip (for this to work, scroll element must be either the root html tag, the tooltip parent, or the anchor parent) |
+| `closeOnResize` | `boolean` | no | `false` | `true` `false` | Resizing the window will close the tooltip |
+| `style` | `CSSProperties` | no | | a CSS style object | Add inline styles directly to the tooltip |
+| `position` | `{ x: number; y: number }` | no | | any `number` value for both `x` and `y` | Override the tooltip position on the DOM |
+| `isOpen` | `boolean` | no | handled by internal state | `true` `false` | The tooltip can be controlled or uncontrolled, this attribute can be used to handle show and hide tooltip outside tooltip (can be used **without** `setIsOpen`) |
+| `setIsOpen` | `function` | no | | | The tooltip can be controlled or uncontrolled, this attribute can be used to handle show and hide tooltip outside tooltip |
+| `afterShow` | `function` | no | | | A function to be called after the tooltip is shown |
+| `afterHide` | `function` | no | | | A function to be called after the tooltip is hidden |
+| `middlewares` | `Middleware[]` | no | | array of valid `floating-ui` middlewares | Allows for advanced customization. Check the [`floating-ui` docs](https://floating-ui.com/docs/middleware) for more information |
+| `border` | `CSSProperties['border']` | no | | a CSS border style | Change the style of the tooltip border (including the arrow) |
+| `opacity` | `CSSProperties['opacity']` | no | `0.9` | a CSS opacity value | Change the opacity of the tooltip |
+| `disableStyleInjection` | `boolean` | `'core'`
| no | `false` | `true` `false` `'core'` | Whether to disable automatic style injection. Do not set dynamically. Check the [styling page](./examples/styling#disabling-reacttooltip-css) for more details |
diff --git a/src/components/TooltipController/TooltipController.tsx b/src/components/TooltipController/TooltipController.tsx
index b5e7c4fd..424b5b11 100644
--- a/src/components/TooltipController/TooltipController.tsx
+++ b/src/components/TooltipController/TooltipController.tsx
@@ -44,6 +44,7 @@ const TooltipController = ({
style,
position,
isOpen,
+ disableStyleInjection = false,
border,
opacity,
setIsOpen,
@@ -63,6 +64,7 @@ const TooltipController = ({
const [tooltipEvents, setTooltipEvents] = useState(events)
const [tooltipPositionStrategy, setTooltipPositionStrategy] = useState(positionStrategy)
const [activeAnchor, setActiveAnchor] = useState(null)
+ const styleInjectionRef = useRef(disableStyleInjection)
/**
* @todo Remove this in a future version (provider/wrapper method is deprecated)
*/
@@ -170,6 +172,29 @@ const TooltipController = ({
setTooltipPositionStrategy(positionStrategy)
}, [positionStrategy])
+ useEffect(() => {
+ if (styleInjectionRef.current === disableStyleInjection) {
+ return
+ }
+ if (process.env.NODE_ENV !== 'production') {
+ // eslint-disable-next-line no-console
+ console.warn('[react-tooltip] Do not change `disableStyleInjection` dynamically.')
+ }
+ }, [disableStyleInjection])
+
+ useEffect(() => {
+ if (typeof window !== 'undefined') {
+ window.dispatchEvent(
+ new CustomEvent('react-tooltip-inject-styles', {
+ detail: {
+ disableCore: disableStyleInjection === 'core',
+ disableBase: disableStyleInjection,
+ },
+ }),
+ )
+ }
+ }, [])
+
useEffect(() => {
const elementRefs = new Set(anchorRefs)
diff --git a/src/components/TooltipController/TooltipControllerTypes.d.ts b/src/components/TooltipController/TooltipControllerTypes.d.ts
index 09adc2b1..371b9e17 100644
--- a/src/components/TooltipController/TooltipControllerTypes.d.ts
+++ b/src/components/TooltipController/TooltipControllerTypes.d.ts
@@ -60,6 +60,7 @@ export interface ITooltipController {
style?: CSSProperties
position?: IPosition
isOpen?: boolean
+ disableStyleInjection?: boolean | 'core'
/**
* @description see https://developer.mozilla.org/en-US/docs/Web/CSS/border.
*
diff --git a/src/index.tsx b/src/index.tsx
index d8c11be7..6dc35544 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -20,8 +20,18 @@ import type { ITooltipWrapper } from './components/TooltipProvider/TooltipProvid
const TooltipCoreStyles = 'react-tooltip-core-css-placeholder'
const TooltipStyles = 'react-tooltip-css-placeholder'
-injectStyle({ css: TooltipCoreStyles, type: 'core' })
-injectStyle({ css: TooltipStyles })
+if (typeof window !== 'undefined') {
+ window.addEventListener('react-tooltip-inject-styles', ((
+ event: CustomEvent<{ disableCore: boolean; disableBase: boolean }>,
+ ) => {
+ if (!event.detail.disableCore) {
+ injectStyle({ css: TooltipCoreStyles, type: 'core' })
+ }
+ if (!event.detail.disableBase) {
+ injectStyle({ css: TooltipStyles, type: 'base' })
+ }
+ }) as EventListener)
+}
export { TooltipController as Tooltip } from './components/TooltipController'
export { TooltipProvider, TooltipWrapper } from './components/TooltipProvider'
diff --git a/src/utils/handle-style.ts b/src/utils/handle-style.ts
index 7deb84ba..8b22d177 100644
--- a/src/utils/handle-style.ts
+++ b/src/utils/handle-style.ts
@@ -3,6 +3,11 @@ const REACT_TOOLTIP_CORE_STYLES_ID = 'react-tooltip-core-styles'
// This is the ID for the visual styles of ReactTooltip
const REACT_TOOLTIP_BASE_STYLES_ID = 'react-tooltip-base-styles'
+const injected = {
+ core: false,
+ base: false,
+}
+
function injectStyle({
css,
id = REACT_TOOLTIP_BASE_STYLES_ID,
@@ -11,10 +16,14 @@ function injectStyle({
}: {
css: string
id?: string
- type?: string
+ type?: 'core' | 'base'
// eslint-disable-next-line @typescript-eslint/no-explicit-any
ref?: any
}) {
+ if (!css || typeof document === 'undefined' || injected[type]) {
+ return
+ }
+
if (
type === 'core' &&
typeof process !== 'undefined' && // this validation prevents docs from breaking even with `process?`
@@ -24,7 +33,7 @@ function injectStyle({
}
if (
- type !== 'core' &&
+ type !== 'base' &&
typeof process !== 'undefined' && // this validation prevents docs from breaking even with `process?`
process?.env?.REACT_TOOLTIP_DISABLE_BASE_STYLES
) {
@@ -42,7 +51,14 @@ function injectStyle({
}
const { insertAt } = ref
- if (!css || typeof document === 'undefined' || document.getElementById(id)) {
+ if (document.getElementById(id)) {
+ // this should never happen because of `injected[type]`
+ if (process.env.NODE_ENV !== 'production') {
+ // eslint-disable-next-line no-console
+ console.warn(
+ `[react-tooltip] Element with id '${id}' already exists. Call \`removeStyle()\` first`,
+ )
+ }
return
}
@@ -67,22 +83,41 @@ function injectStyle({
} else {
style.appendChild(document.createTextNode(css))
}
+
+ injected[type] = true
}
+/**
+ * @deprecated Use the `disableStyleInjection` tooltip prop instead.
+ * See https://react-tooltip.com/docs/examples/styling#disabling-reacttooltip-css
+ */
function removeStyle({
type = 'base',
id = REACT_TOOLTIP_BASE_STYLES_ID,
}: {
- type?: string
+ type?: 'core' | 'base'
id?: string
} = {}) {
+ if (!injected[type]) {
+ return
+ }
+
if (type === 'core') {
// eslint-disable-next-line no-param-reassign
id = REACT_TOOLTIP_CORE_STYLES_ID
}
const style = document.getElementById(id)
- style?.remove()
+ if (style?.tagName === 'style') {
+ style?.remove()
+ } else if (process.env.NODE_ENV !== 'production') {
+ // eslint-disable-next-line no-console
+ console.warn(
+ `[react-tooltip] Failed to remove 'style' element with id '${id}'. Call \`injectStyle()\` first`,
+ )
+ }
+
+ injected[type] = false
}
export { injectStyle, removeStyle }