diff --git a/apps/website/src/routes/docs/headless/tooltip/examples/onChange.tsx b/apps/website/src/routes/docs/headless/tooltip/examples/onChange.tsx
new file mode 100644
index 000000000..a701eb20a
--- /dev/null
+++ b/apps/website/src/routes/docs/headless/tooltip/examples/onChange.tsx
@@ -0,0 +1,19 @@
+import { component$, useSignal } from '@builder.io/qwik';
+import { Tooltip } from '@qwik-ui/headless';
+
+export default component$(() => {
+ const tooltipState = useSignal<'open' | 'closed'>('closed');
+
+ return (
+ <>
+ (tooltipState.value = e)} flip>
+ Hover or Focus me
+
+
+ Tooltip content here
+
+
+ The tooltip is {tooltipState.value}
+ >
+ );
+});
diff --git a/apps/website/src/routes/docs/headless/tooltip/index.mdx b/apps/website/src/routes/docs/headless/tooltip/index.mdx
index 0bf2b191f..ce01194eb 100644
--- a/apps/website/src/routes/docs/headless/tooltip/index.mdx
+++ b/apps/website/src/routes/docs/headless/tooltip/index.mdx
@@ -199,6 +199,13 @@ CSS from the example:
+## Events
+
+The tooltip contains a `onOpenChange$` event that runs when the tooltip opens or closes.
+This can be used to trigger additional actions when the tooltip is opened or closed.
+
+
+
## Additional References
Qwik UI aims to be in line with the standard whenever possible. Our goal is to empower Qwik developers to create amazing experiences for their users.
@@ -255,6 +262,12 @@ To read more about tooltips you can check it out on:
type: 'selector',
description: 'Style the element when the tooltip is open.',
},
+ {
+ name: 'onOpenChange$',
+ type: 'QRL',
+ description: 'QRL handler that runs when the tooltip opens or closes.',
+ info: 'QRL<(state: "open" | "closed") => void>',
+ },
]}
/>
diff --git a/packages/kit-headless/src/components/tooltip/tooltip-context.ts b/packages/kit-headless/src/components/tooltip/tooltip-context.ts
index 160aa1d75..fcef105ab 100644
--- a/packages/kit-headless/src/components/tooltip/tooltip-context.ts
+++ b/packages/kit-headless/src/components/tooltip/tooltip-context.ts
@@ -1,4 +1,4 @@
-import { createContextId, Signal } from '@builder.io/qwik';
+import { createContextId, QRL, Signal } from '@builder.io/qwik';
export const TooltipContextId = createContextId('Tooltip');
@@ -11,6 +11,8 @@ export type TooltipContext = {
triggerRef: Signal;
state: Signal;
+
+ onOpenChange$: QRL<(state: 'open' | 'closed') => void>;
};
export type TriggerDataState = 'closing' | 'closed' | 'opening' | 'open';
diff --git a/packages/kit-headless/src/components/tooltip/tooltip-panel.tsx b/packages/kit-headless/src/components/tooltip/tooltip-panel.tsx
index dbbc01d54..898e02c8c 100644
--- a/packages/kit-headless/src/components/tooltip/tooltip-panel.tsx
+++ b/packages/kit-headless/src/components/tooltip/tooltip-panel.tsx
@@ -11,7 +11,12 @@ export const HTooltipPanel = component$((props: HTooltipPanelProps) => {
const context = useContext(TooltipContextId);
return (
-
+ context.onOpenChange$(e.newState)}
+ id={context.localId}
+ >
);
diff --git a/packages/kit-headless/src/components/tooltip/tooltip-root.tsx b/packages/kit-headless/src/components/tooltip/tooltip-root.tsx
index b3affacce..c3b74809b 100644
--- a/packages/kit-headless/src/components/tooltip/tooltip-root.tsx
+++ b/packages/kit-headless/src/components/tooltip/tooltip-root.tsx
@@ -7,6 +7,7 @@ import {
useContextProvider,
useId,
useSignal,
+ $,
} from '@builder.io/qwik';
import { FloatingProps, HPopoverRoot } from '../popover/popover-root';
import { TooltipContext, TooltipContextId, TriggerDataState } from './tooltip-context';
@@ -27,7 +28,7 @@ export type TooltipRootProps = {
* QRL handler that runs when the tooltip opens or closes.
* @param open The new state of the tooltip.
*/
- onOpenChange$?: QRL<(state: TriggerDataState) => void>;
+ onOpenChange$?: QRL<(state: 'open' | 'closed') => void>;
/**
* A value that determines how long before the tooltip will
@@ -58,7 +59,7 @@ export const HTooltipRoot = component$((props: TooltipProps) => {
gutter,
delayDuration = 0,
flip,
- onOpenChange$: _,
+ onOpenChange$,
...rest
} = props;
@@ -74,6 +75,7 @@ export const HTooltipRoot = component$((props: TooltipProps) => {
triggerRef,
delayDuration,
state: tooltipState,
+ onOpenChange$: $((e) => onOpenChange$?.(e)),
};
useContextProvider(TooltipContextId, context);
diff --git a/packages/kit-headless/src/components/tooltip/tooltip.driver.ts b/packages/kit-headless/src/components/tooltip/tooltip.driver.ts
index 4c753a3d2..705cdbabd 100644
--- a/packages/kit-headless/src/components/tooltip/tooltip.driver.ts
+++ b/packages/kit-headless/src/components/tooltip/tooltip.driver.ts
@@ -51,6 +51,10 @@ export function createTooltipDriver(rootLocator: T) {
return getTrigger().all();
};
+ const getOnChangeVerificationText = (state: 'open' | 'closed') => {
+ return rootLocator.getByText(`The tooltip is ${state}`);
+ };
+
const getProgrammaticButtonTrigger = () => {
return rootLocator.locator('button');
};
@@ -65,5 +69,6 @@ export function createTooltipDriver(rootLocator: T) {
openTooltip,
getProgrammaticButtonTrigger,
getTooltipByTextContent,
+ getOnChangeVerificationText,
};
}
diff --git a/packages/kit-headless/src/components/tooltip/tooltip.test.ts b/packages/kit-headless/src/components/tooltip/tooltip.test.ts
index b7b49dc95..5c10c1b0e 100644
--- a/packages/kit-headless/src/components/tooltip/tooltip.test.ts
+++ b/packages/kit-headless/src/components/tooltip/tooltip.test.ts
@@ -221,3 +221,20 @@ test.describe('Tooltip Animations', () => {
await expect(tooltip).toBeHidden();
});
});
+
+test.describe('Tooltip Events', () => {
+ test(`GIVEN a tooltip with opOpenChange configured
+ WHEN hovering over the trigger
+ THEN the text should say "The tooltip is open"`, async ({ page }) => {
+ const { driver: d } = await setup(page, 'onChange');
+ const tooltip = d.getTooltip();
+ const trigger = d.getTrigger();
+
+ expect(d.getOnChangeVerificationText('closed')).toBeVisible();
+
+ await trigger.hover();
+ await expect(tooltip).toBeVisible();
+
+ expect(d.getOnChangeVerificationText('open')).toBeVisible();
+ });
+});