From 33f3d9db53d58a44f169a3ac65fb78c136ee0850 Mon Sep 17 00:00:00 2001 From: Adam Bowker Date: Fri, 13 Feb 2026 20:47:16 -0800 Subject: [PATCH] feat(product tours): add banner animations --- .changeset/wet-hands-roll.md | 5 +++++ .../components/ProductTourBanner.tsx | 12 +++++++++++- .../extensions/product-tours/product-tour.css | 19 +++++++++++++++++++ .../product-tours/product-tours.tsx | 6 +++++- .../src/posthog-product-tours-types.ts | 3 +++ playground/nextjs/pages/product-tours.tsx | 2 ++ 6 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 .changeset/wet-hands-roll.md diff --git a/.changeset/wet-hands-roll.md b/.changeset/wet-hands-roll.md new file mode 100644 index 0000000000..96c6652b3d --- /dev/null +++ b/.changeset/wet-hands-roll.md @@ -0,0 +1,5 @@ +--- +'posthog-js': patch +--- + +add animation option for tour banners diff --git a/packages/browser/src/extensions/product-tours/components/ProductTourBanner.tsx b/packages/browser/src/extensions/product-tours/components/ProductTourBanner.tsx index 50c7a3f14a..5b9b2c2d45 100644 --- a/packages/browser/src/extensions/product-tours/components/ProductTourBanner.tsx +++ b/packages/browser/src/extensions/product-tours/components/ProductTourBanner.tsx @@ -56,7 +56,17 @@ function StaticWrapper({ class: className, children }: BannerWrapperProps): h.JS return
{children}
} -export function ProductTourBanner({ +export function ProductTourBanner(props: ProductTourBannerProps) { + return ( +
+
+ +
+
+ ) +} + +function ProductTourBannerInner({ step, onDismiss, onActionClick, diff --git a/packages/browser/src/extensions/product-tours/product-tour.css b/packages/browser/src/extensions/product-tours/product-tour.css index 97048e1859..49b401ade8 100644 --- a/packages/browser/src/extensions/product-tours/product-tour.css +++ b/packages/browser/src/extensions/product-tours/product-tour.css @@ -560,6 +560,25 @@ } /* Banner styles */ +@keyframes ph-tour-banner-slide-in { + from { + grid-template-rows: 0fr; + } + to { + grid-template-rows: 1fr; + } +} + +.ph-tour-banner-wrapper { + display: grid; + animation: ph-tour-banner-slide-in var(--ph-tour-banner-animation-duration, 300ms) ease-out forwards; +} + +.ph-tour-banner-slide { + overflow: hidden; + min-height: 0; +} + .ph-tour-banner { display: flex; align-items: center; diff --git a/packages/browser/src/extensions/product-tours/product-tours.tsx b/packages/browser/src/extensions/product-tours/product-tours.tsx index d8205976d9..b1b66106a0 100644 --- a/packages/browser/src/extensions/product-tours/product-tours.tsx +++ b/packages/browser/src/extensions/product-tours/product-tours.tsx @@ -30,7 +30,7 @@ import { createLogger } from '../../utils/logger' import { document as _document, window as _window } from '../../utils/globals' import { localStore, sessionStore } from '../../storage' import { addEventListener } from '../../utils' -import { isNull, SurveyMatchType } from '@posthog/core' +import { isNull, isUndefined, SurveyMatchType } from '@posthog/core' import { propertyComparisons } from '../../utils/property-utils' import { TOUR_SHOWN_KEY_PREFIX, @@ -154,6 +154,10 @@ function retrieveBannerShadow( addProductTourCSSVariablesToElement(div, tour.appearance) + if (!isUndefined(bannerConfig?.animation?.duration)) { + div.style.setProperty('--ph-tour-banner-animation-duration', `${bannerConfig.animation.duration}ms`) + } + const shadow = div.attachShadow({ mode: 'open' }) const stylesheet = getProductTourStylesheet() diff --git a/packages/browser/src/posthog-product-tours-types.ts b/packages/browser/src/posthog-product-tours-types.ts index 4973b65808..654dfdb9c5 100644 --- a/packages/browser/src/posthog-product-tours-types.ts +++ b/packages/browser/src/posthog-product-tours-types.ts @@ -22,6 +22,9 @@ export interface ProductTourBannerConfig { link?: string tourId?: string } + animation?: { + duration?: number + } } /** Button actions available on modal steps */ diff --git a/playground/nextjs/pages/product-tours.tsx b/playground/nextjs/pages/product-tours.tsx index 90a8801baf..d2f7cb1310 100644 --- a/playground/nextjs/pages/product-tours.tsx +++ b/playground/nextjs/pages/product-tours.tsx @@ -53,6 +53,8 @@ export default function ProductTours() { return (
+
+

Product Tours Playground

{/* Tour Controls */}