diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/tooltip/properties.md b/packages/dnb-design-system-portal/src/docs/uilib/components/tooltip/properties.md
index 819e9c14305..ea00333918a 100644
--- a/packages/dnb-design-system-portal/src/docs/uilib/components/tooltip/properties.md
+++ b/packages/dnb-design-system-portal/src/docs/uilib/components/tooltip/properties.md
@@ -4,20 +4,21 @@ showTabs: true
## Tooltip properties
-| Properties | Description |
-| ------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `children` | _(optional)_ Provide a string or a React Element to be shown as the tooltip content. |
-| `active` | _(optional)_ set to `true` the tooltip will show up. |
+| Properties | Description |
+| ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `children` | _(optional)_ Provide a string or a React Element to be shown as the tooltip content. |
+| `active` | _(optional)_ set to `true` the tooltip will show up. |
| `position` | _(optional)_ defines the offset position to the target element the arrow appears. Can be `top`, `right`, `left` and `bottom`. Defaults to `top`. |
| `position` | _(optional)_ defines the offset position to the target element the arrow appears. Can be `top`, `right`, `left` and `bottom`. Defaults to `top`. |
| `align` | _(optional)_ defines the offset alignment to the target element the arrow appears. Can be `center`, `right` and `left`.Defaults to `center`. |
-| `arrow` | _(optional)_ defines the direction where the arrow appears. Can be `center`, `top`, `right`, `bottom` and `left`. Defaults to `center`. |
-| `fixed_position` | _(optional)_ If set to `true`, the Tooltip will be fixed in its scroll position by using CSS `position: fixed;`. Defaults to `false`. |
-| `no_animation` | _(optional)_ set to `true` if no fade-in animation should be used. |
-| `show_delay` | _(optional)_ define the delay until the tooltip should show up after the initial hover / active state. |
-| `hide_delay` | _(optional)_ define the delay until the tooltip should disappear up after initial visibility. |
-| `target_element` | _(optional)_ provide an element directly as a React Node or a React Ref that will be wrapped and rendered. |
-| `target_selector` | _(optional)_ specify a vanilla HTML selector by a string as the target element. |
-| `size` | _(optional)_ defines the spacing size of the tooltip. Can be `large` or `basis`. Defaults to `basis`. |
-| `group` | _(optional)_ if the tooltip should animate from one target to the next, define a unique ID. |
-| [Space](/uilib/components/space/properties) | _(optional)_ spacing properties like `top` or `bottom` are supported. |
+| `arrow` | _(optional)_ defines the direction where the arrow appears. Can be `center`, `top`, `right`, `bottom` and `left`. Defaults to `center`. |
+| `fixed_position` | _(optional)_ If set to `true`, the Tooltip will be fixed in its scroll position by using CSS `position: fixed;`. Defaults to `false`. |
+| `skip_portal` | _(optional)_ set to `true` to disable the React Portal behavior. Defaults to `false`. |
+| `no_animation` | _(optional)_ set to `true` if no fade-in animation should be used. |
+| `show_delay` | _(optional)_ define the delay until the tooltip should show up after the initial hover / active state. |
+| `hide_delay` | _(optional)_ define the delay until the tooltip should disappear up after initial visibility. |
+| `target_element` | _(optional)_ provide an element directly as a React Node or a React Ref that will be wrapped and rendered. |
+| `target_selector` | _(optional)_ specify a vanilla HTML selector by a string as the target element. |
+| `size` | _(optional)_ defines the spacing size of the tooltip. Can be `large` or `basis`. Defaults to `basis`. |
+| `group` | _(optional)_ if the tooltip should animate from one target to the next, define a unique ID. |
+| [Space](/uilib/components/space/properties) | _(optional)_ spacing properties like `top` or `bottom` are supported. |
diff --git a/packages/dnb-eufemia/src/components/dialog/__tests__/__snapshots__/Dialog.test.tsx.snap b/packages/dnb-eufemia/src/components/dialog/__tests__/__snapshots__/Dialog.test.tsx.snap
index b14fd3871c0..2f063c5ebd3 100644
--- a/packages/dnb-eufemia/src/components/dialog/__tests__/__snapshots__/Dialog.test.tsx.snap
+++ b/packages/dnb-eufemia/src/components/dialog/__tests__/__snapshots__/Dialog.test.tsx.snap
@@ -439,6 +439,7 @@ exports[`Dialog component snapshot should match component snapshot 1`] = `
position="top"
show_delay={300}
size="basis"
+ skip_portal={null}
target_element={
Object {
"current": }
- >
- Text
-
- )
- it('have to match default tooltip snapshot', () => {
- const Comp = mount()
- expect(toJson(Comp)).toMatchSnapshot()
- })
-
- it('should validate with ARIA rules as a tooltip', async () => {
- const Comp = mount()
- expect(await axeComponent(Comp)).toHaveNoViolations()
- })
+beforeEach(() => {
+ document.body.innerHTML = ''
})
-describe('Tooltip component with target', () => {
- const Component = (props = {}) => (
- <>
-
-
- Text
-
- >
- )
-
- it('has to be in the DOM so aria-describedby is valid', () => {
- const Comp = mount(
-
- text
-
- )
-
- const id = Comp.find('a').instance().getAttribute('aria-describedby')
- expect(document.body.querySelectorAll('#' + id).length).toBe(1)
- })
-
- it('has to be visible on hover', async () => {
- const Comp = mount(
-
- text
-
+describe('Tooltip', () => {
+ describe('with target', () => {
+ const Component = (props = {}) => (
+ <>
+
+
+ Text
+
+ >
)
- // hover
- Comp.find('a').instance().dispatchEvent(new MouseEvent('mouseenter'))
-
- await wait(100)
-
- const id = Comp.find('a').instance().getAttribute('aria-describedby')
- expect(
- document.body
- .querySelector('#' + id)
- .parentElement.classList.contains('dnb-tooltip--active')
- ).toBe(true)
-
- // leave hover
- Comp.find('a').instance().dispatchEvent(new MouseEvent('mouseleave'))
-
- await wait(600)
-
- expect(
- document.body
- .querySelector('#' + id)
- .parentElement.classList.contains('dnb-tooltip--active')
- ).toBe(false)
+ it('creates a React Portal', () => {
+ mount(, {
+ attachTo: attachToBody(),
+ })
+
+ expect(
+ document.body.querySelectorAll('.dnb-tooltip__portal')
+ ).toHaveLength(1)
+ expect(document.body.querySelectorAll('.dnb-tooltip')).toHaveLength(
+ 1
+ )
+ })
+
+ it('will skip React Portal when skip_portal is true', () => {
+ const Comp = mount(, {
+ attachTo: attachToBody(),
+ })
+
+ expect(
+ document.body.querySelectorAll('.dnb-tooltip__portal')
+ ).toHaveLength(0)
+
+ expect(toJson(Comp.find('.dnb-tooltip'))).toMatchSnapshot()
+ })
+
+ it('should validate with ARIA rules as a tooltip', async () => {
+ const Comp = mount()
+ expect(await axeComponent(Comp)).toHaveNoViolations()
+ })
})
- it('has to be visible on focus event dispatch', async () => {
- const Comp = mount(
-
- text
-
+ describe('with target_element', () => {
+ const Component = (props = {}) => (
+ Button}
+ >
+ Text
+
)
- document.documentElement.setAttribute('data-whatintent', 'keyboard')
- const inst = Comp.find('a').instance()
- inst.dispatchEvent(new Event('focus'))
+ it('have to match default tooltip snapshot', () => {
+ const Comp = mount()
+ expect(toJson(Comp)).toMatchSnapshot()
+ })
- await wait(400) // because of visibility delay
-
- const id = inst.getAttribute('aria-describedby')
- expect(
- document.body
- .querySelector('#' + id)
- .parentElement.classList.contains('dnb-tooltip--active')
- ).toBe(true)
+ it('should validate with ARIA rules as a tooltip', async () => {
+ const Comp = mount()
+ expect(await axeComponent(Comp)).toHaveNoViolations()
+ })
})
- it('should validate with ARIA rules as a tooltip', async () => {
- const Comp = mount()
- expect(await axeComponent(Comp)).toHaveNoViolations()
+ describe('Anchor with tooltip', () => {
+ it('has to be in the DOM so aria-describedby is valid', () => {
+ const Comp = mount(
+
+ text
+
+ )
+
+ const id = Comp.find('a').instance().getAttribute('aria-describedby')
+ expect(document.body.querySelectorAll('#' + id).length).toBe(1)
+ })
+
+ it('has to be visible on hover', async () => {
+ const Comp = mount(
+
+ text
+
+ )
+
+ // hover
+ Comp.find('a').instance().dispatchEvent(new MouseEvent('mouseenter'))
+
+ await wait(100)
+
+ const id = Comp.find('a').instance().getAttribute('aria-describedby')
+ expect(
+ document.body
+ .querySelector('#' + id)
+ .parentElement.classList.contains('dnb-tooltip--active')
+ ).toBe(true)
+
+ // leave hover
+ Comp.find('a').instance().dispatchEvent(new MouseEvent('mouseleave'))
+
+ await wait(600)
+
+ expect(
+ document.body
+ .querySelector('#' + id)
+ .parentElement.classList.contains('dnb-tooltip--active')
+ ).toBe(false)
+ })
+
+ it('has to be visible on focus event dispatch', async () => {
+ const Comp = mount(
+
+ text
+
+ )
+
+ document.documentElement.setAttribute('data-whatintent', 'keyboard')
+ const inst = Comp.find('a').instance()
+ inst.dispatchEvent(new Event('focus'))
+
+ await wait(400) // because of visibility delay
+
+ const id = inst.getAttribute('aria-describedby')
+ expect(
+ document.body
+ .querySelector('#' + id)
+ .parentElement.classList.contains('dnb-tooltip--active')
+ ).toBe(true)
+ })
})
})
@@ -130,6 +166,7 @@ describe('Tooltip scss', () => {
const scss = loadScss(require.resolve('../style/dnb-tooltip.scss'))
expect(scss).toMatchSnapshot()
})
+
it('have to match default theme snapshot', () => {
const scss = loadScss(
require.resolve('../style/themes/dnb-tooltip-theme-ui.scss')
diff --git a/packages/dnb-eufemia/src/components/tooltip/__tests__/__snapshots__/Tooltip.test.js.snap b/packages/dnb-eufemia/src/components/tooltip/__tests__/__snapshots__/Tooltip.test.js.snap
index 9bec5ef08ee..6e3924e69a2 100644
--- a/packages/dnb-eufemia/src/components/tooltip/__tests__/__snapshots__/Tooltip.test.js.snap
+++ b/packages/dnb-eufemia/src/components/tooltip/__tests__/__snapshots__/Tooltip.test.js.snap
@@ -1,112 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`Tooltip component with target_element have to match default tooltip snapshot 1`] = `
-
-
- Button
-
- }
- target_selector={null}
- tooltip={null}
- >
-
- Button
-
- }
- target_element={
-
- }
- target_selector={null}
- tooltip={null}
- >
-
-
- Button
-
- }
- target_element={
-
- }
- target_selector={null}
- tooltip={null}
- />
-
-
-
-`;
-
exports[`Tooltip scss have to match default theme snapshot 1`] = `
"/*
* Tooltip theme
@@ -288,3 +181,137 @@ exports[`Tooltip scss have to match snapshot 1`] = `
visibility: hidden; } }
"
`;
+
+exports[`Tooltip with target will skip React Portal when skip_portal is true 1`] = `
+
+
+
+ Text
+
+
+`;
+
+exports[`Tooltip with target_element have to match default tooltip snapshot 1`] = `
+
+
+ Button
+
+ }
+ target_selector={null}
+ tooltip={null}
+ >
+
+ Button
+
+ }
+ target_element={
+
+ }
+ target_selector={null}
+ tooltip={null}
+ >
+
+
+ Button
+
+ }
+ target_element={
+
+ }
+ target_selector={null}
+ tooltip={null}
+ />
+
+
+
+`;