Skip to content

feat(react-headless-components-preview): add TeachingPopover #36205

Open
mainframev wants to merge 4 commits into
microsoft:masterfrom
mainframev:feat/headless-add-teaching-popover
Open

feat(react-headless-components-preview): add TeachingPopover #36205
mainframev wants to merge 4 commits into
microsoft:masterfrom
mainframev:feat/headless-add-teaching-popover

Conversation

@mainframev
Copy link
Copy Markdown
Contributor

@mainframev mainframev commented May 13, 2026

Adds a new headless TeachingPopover exposed at the
@fluentui/react-headless-components-preview/teaching-popover subpath

How it composes

  • useTeachingPopover builds on the headless usePopover and defaults
    withArrow: true to match the v9 component.
  • Sub‑components re‑export the v9 *Base_unstable hooks introduced in feat(react-teaching-popover): add base hooks and export them #36200
    (useTeachingPopoverHeaderBase_unstable, useTeachingPopoverTitleBase_unstable,
    useTeachingPopoverFooterBase_unstable, useTeachingPopoverCarouselBase_unstable,
    etc.), keeping all behavior (dismiss handlers, finish handlers, carousel state
    machine) while dropping the styled appearance, default icons, and primary /
    secondary Button slots.
  • renderTeachingPopover bridges the headless PopoverProvider and the v9
    PopoverProvider so v9 base sub‑hooks can read context transparently.
  • TeachingPopoverFooter ships a local render that emits only <state.root />
    (no primary / secondary Button slots — consumer composes any buttons).
  • TeachingPopoverCarouselFooter ships a local hook + render returning only
    { root } for the same reason.

Not in scope

  • No styling shipped from the library (intentional — headless package contract).
  • appearance, trapFocus (TBA), and inline props from the v9 component are
    intentionally dropped

Stories

Two stories under stories/src/TeachingPopover/:

  • Default — header (icon + label + dismiss), media placeholder, title, body,
    primary + secondary footer.
  • WithCarousel — three‑card tour with nav buttons, page count, and prev / next
    controls.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 13, 2026

📊 Bundle size report

✅ No changes found

@github-actions
Copy link
Copy Markdown

Pull request demo site: URL

@@ -0,0 +1,7 @@
{
Copy link
Copy Markdown

@github-actions github-actions Bot May 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🕵🏾‍♀️ visual changes to review in the Visual Change Report

vr-tests-react-components/CalendarCompat 4 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/CalendarCompat.multiDayView.default.chromium_1.png 487 Changed
vr-tests-react-components/CalendarCompat.multiDayView.default.chromium.png 486 Changed
vr-tests-react-components/CalendarCompat.multiDayView - High Contrast.default.chromium.png 1213 Changed
vr-tests-react-components/CalendarCompat.multiDayView - Dark Mode.default.chromium.png 1099 Changed
vr-tests-react-components/Menu Converged - submenuIndicator slotted content 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Menu Converged - submenuIndicator slotted content.default - RTL.submenus open.chromium.png 404 Changed
vr-tests-react-components/Menu Converged - submenuIndicator slotted content.default.submenus open.chromium.png 413 Changed
vr-tests-react-components/Positioning 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Positioning.Positioning end.chromium.png 744 Changed
vr-tests-react-components/Positioning.Positioning end.updated 2 times.chromium.png 613 Changed
vr-tests-react-components/ProgressBar converged 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/ProgressBar converged.Indeterminate + thickness - Dark Mode.default.chromium.png 51 Changed
vr-tests-react-components/ProgressBar converged.Indeterminate + thickness - High Contrast.default.chromium.png 52 Changed
vr-tests-react-components/TagPicker 3 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/TagPicker.disabled.chromium.png 677 Changed
vr-tests-react-components/TagPicker.disabled - Dark Mode.disabled input hover.chromium.png 658 Changed
vr-tests-react-components/TagPicker.disabled - High Contrast.disabled input hover.chromium.png 1319 Changed

There were 4 duplicate changes discarded. Check the build logs for more information.

@mainframev mainframev force-pushed the feat/headless-add-teaching-popover branch from 086563e to 67884ed Compare May 18, 2026 10:41
@mainframev mainframev marked this pull request as ready for review May 18, 2026 11:34
@mainframev mainframev requested a review from a team as a code owner May 18, 2026 11:34
@@ -0,0 +1,37 @@
import type { PopoverContextValue as V9PopoverContextValue } from '@fluentui/react-popover';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, but lets use Base or Fluent prefix/suffix instead of v9

state: TeachingPopoverState,
contextValues: TeachingPopoverContextValues,
): React.ReactElement => (
<PopoverProvider value={contextValues.popover}>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's unfortunate that headless popover doesn't re-use v9's context provider, that would simplify cases like this

* Cast around the v9 contextValues helper, which is typed against the
* styled state but only reads carousel fields that exist on the base state.
*/
export const useTeachingPopoverCarouselContextValues = (
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can type-cast without creating a wrapper:

Suggested change
export const useTeachingPopoverCarouselContextValues = (
export const useTeachingPopoverCarouselContextValues = useTeachingPopoverCarouselContextValues_unstable as (state: TeachingPopoverCarouselState) => TeachingPopoverCarouselContextValues

export const renderTeachingPopoverCarouselFooterButton = (
state: TeachingPopoverCarouselFooterButtonState,
): JSXElement =>
renderTeachingPopoverCarouselFooterButton_unstable(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the same as above, lets type-cast without wrapping a hook

import type { TeachingPopoverCarouselNavButtonState } from './TeachingPopoverCarouselNavButton.types';

export const renderTeachingPopoverCarouselNavButton = (state: TeachingPopoverCarouselNavButtonState): JSXElement =>
renderTeachingPopoverCarouselNavButton_unstable(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and here, lets type-cast without creating a wrapper

@@ -0,0 +1,3 @@
The headless `TeachingPopover` is built on top of the headless `Popover`. It adds a structured header / title / body / footer composition and an optional paged carousel — without styling. Bring your own CSS.

`TeachingPopover` re-uses the v9 `react-teaching-popover` base hooks for its sub-components (`Header`, `Title`, `Footer`, `Carousel*`) and bridges the v9 `PopoverContext` internally so dismiss buttons, finish handlers, and the carousel state machine all work transparently.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

v9 might not be clear to everyone, we should probably use @fluentui/react-teaching-popover

TeachingPopoverTrigger,
} from '@fluentui/react-headless-components-preview/teaching-popover';

import styles from './teaching-popover.module.css';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we re-use popover styles

import styles from './teaching-popover.module.css';
import popoverStyles from '../Popover/popover.module.css';

@mainframev mainframev requested a review from dmytrokirpa May 19, 2026 12:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants