Skip to content

Replace content analysis buttons with ui-library Button#23051

Open
JorPV wants to merge 9 commits intoyst-root-clean-up-from-pluginfrom
worktree-replace-content-analysis-buttons
Open

Replace content analysis buttons with ui-library Button#23051
JorPV wants to merge 9 commits intoyst-root-clean-up-from-pluginfrom
worktree-replace-content-analysis-buttons

Conversation

@JorPV
Copy link
Copy Markdown
Contributor

@JorPV JorPV commented Mar 5, 2026

Context

As part of the effort to move away from legacy @yoast/components, this PR replaces the Highlight (mark) button and Edit button in content analysis results with the Button component from @yoast/ui-library, using @heroicons/react icons (EyeIcon, PencilIcon). It also replaces the legacy CSS tooltip classes with the TooltipContainer/TooltipWithContext components from @yoast/ui-library, providing keyboard-accessible tooltips.

Summary

This PR can be summarized in the following changelog entry:

  • changelog: enhancement - Replaces legacy IconButtonToggle and IconCTAEditButton components with @yoast/ui-library Button, TooltipContainer, and @heroicons/react icons in content analysis results.

Relevant technical choices:

Button replacement

  • Replaced IconButtonToggle (highlight button) with Button variant="secondary"/"primary" size="small" + EyeIcon from @heroicons/react/outline
  • Replaced IconCTAEditButton (edit button) with Button variant="secondary" size="small" + PencilIcon from @heroicons/react/outline
  • Button styling uses yst-px-2 yst-rounded-md yst-shadow-none yst-border-0 to match the AI optimize button appearance
  • Highlight button toggles between variant="secondary" (unpressed) and variant="primary" (pressed)

Tooltip replacement

  • Uses TooltipContainer/useTooltipContext()/TooltipWithContext from @yoast/ui-library
  • MarkButtonInner and EditButtonInner components consume useTooltipContext() for show/hide
  • Tooltips support both pointer (onPointerEnter/onPointerLeave) and keyboard (onFocus/onBlur)
  • Proper aria-describedby wiring links buttons to their tooltips
  • Mark button tooltip is hidden when pressed (active highlighting state)
  • TooltipContainer provides Escape key dismissal automatically
  • Each button+tooltip pair is wrapped in <Root> from @yoast/ui-library to ensure the Tailwind preflight CSS (.yst-root ::before { border-width: 0 }) is properly scoped, which is required for the tooltip arrow to render correctly

Component restructuring

  • MarkButtonInner + MarkButton wrapper pattern in AnalysisResult.js
  • EditButtonInner component in AnalysisResult.js
  • MarkButtonInner + MarkButtonWithUpsell wrapper pattern in Results.js
  • Null guard added to TooltipWithContext in tooltip-container for test compatibility
  • Removed now-unnecessary marksButtonClassName="" and editButtonClassName="" props from SeoAnalysis.js, ReadabilityAnalysis.js, and InclusiveLanguageAnalysis.js (the defaults in Results.js are already "")

Dependencies

  • Added @heroicons/react, @yoast/ui-library, and classnames as dependencies to @yoast/analysis-report package.json

Test instructions

Test instructions for the acceptance test before the PR gets merged

This PR can be acceptance tested by following these steps:

  • Open a post/page in the editor (Block or Classic)
  • Verify the SEO analysis and Readability analysis results display correctly
  • Verify the highlight (eye) button renders with the outlined eye icon and is clickable
  • Verify hovering over the highlight button shows a tooltip with "Highlight this result in the text" and a left-pointing arrow
  • Verify clicking the highlight button toggles text highlighting in the editor and the button switches to primary (filled) style
  • Verify the tooltip is hidden when the button is in pressed/active state
  • Verify the highlight button shows a disabled state when appropriate (e.g. when shortcodes are being parsed)
  • Verify the edit (pencil) button renders with the outlined pencil icon and is clickable (Premium only)
  • Verify hovering over the edit button shows a tooltip with the appropriate label and arrow
  • Verify clicking the edit button navigates to the relevant input field
  • Verify tooltip appears when tabbing to the highlight/edit button (keyboard focus)
  • Verify tooltip disappears when tabbing away (blur)
  • Verify pressing Escape dismisses the tooltip
  • Verify the upsell badge (lock icon) still appears on the highlight button for free users
  • Verify the AI Optimize button still works alongside the new buttons and all buttons are visually consistent in size and style

Relevant test scenarios

  • Changes should be tested with the browser console open
  • Changes should be tested on different editors (Default Block/Gutenberg/Classic/Elementor/other)
  • Changes should be tested on different browsers

Test instructions for QA when the code is in the RC

  • QA should use the same steps as above.

Impact check

This PR affects the following parts of the plugin, which may require extra testing:

  • Content analysis results buttons (highlight and edit) in the SEO and Readability analysis panels
  • Tooltip rendering on highlight and edit buttons

Other environments

  • This PR also affects Shopify.
  • This PR also affects Yoast SEO for Google Docs.

Documentation

  • I have written documentation for this change.

Quality assurance

  • I have tested this code to the best of my abilities.
  • During testing, I had activated all plugins that Yoast SEO provides integrations for.
  • I have added unit tests to verify the code works as intended.
  • If any part of the code is behind a feature flag, my test instructions also cover cases where the feature flag is switched off.
  • I have written this PR in accordance with my team's definition of done.
  • I have checked that the base branch is correctly set.
  • I have run grunt build:images and commited the results, if my PR introduces new images or SVGs.

Innovation

  • No innovation project is applicable for this PR.
  • This PR falls under an innovation project. I have attached the innovation label.
  • I have added my hours to the WBSO document.

@JorPV JorPV added the changelog: non-user-facing Needs to be included in the 'Non-userfacing' category in the changelog label Mar 5, 2026
@JorPV JorPV force-pushed the yst-root-clean-up-from-plugin branch from 260fee1 to 6c684de Compare March 6, 2026 09:09
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 6, 2026

A merge conflict has been detected for the proposed code changes in this PR. Please resolve the conflict by either rebasing the PR or merging in changes from the base branch.

@JorPV JorPV force-pushed the yst-root-clean-up-from-plugin branch from 6c684de to 5b7749f Compare March 6, 2026 09:22
@JorPV JorPV requested a review from a team as a code owner March 6, 2026 10:53
@JorPV JorPV force-pushed the yst-root-clean-up-from-plugin branch from 5b7749f to ed385e2 Compare March 9, 2026 15:01
@JorPV JorPV requested a review from Copilot March 11, 2026 16:08
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR continues the UI migration away from legacy @yoast/components by replacing content analysis “highlight” and “edit” buttons with @yoast/ui-library Button + @heroicons/react icons, and updates the analysis-report package dependencies accordingly.

Changes:

  • Replace legacy content analysis mark/edit icon buttons with @yoast/ui-library Button implementations (including tooltip handling).
  • Add @heroicons/react, classnames, and @yoast/ui-library dependencies to @yoast/analysis-report.
  • Minor cleanup: update some JSDoc defaults and remove several yst-root wrapper elements across UI components.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
packages/js/src/settings/components/formik-user-select-field.js JSDoc default value for className.
packages/js/src/settings/components/formik-page-select-field.js JSDoc default value for className.
packages/js/src/settings/components/formik-media-select-field.js JSDoc default value for className.
packages/js/src/settings/components/formik-indexable-page-select-field.js JSDoc default value for className.
packages/js/src/installation-success.js Removes yst-root class from the page root wrapper.
packages/js/src/components/modals/KeywordUpsell.js Removes yst-root wrapper divs around upsell badges.
packages/js/src/components/modals/InternalLinkingSuggestionsUpsell.js Removes yst-root wrapper divs around upsell badges.
packages/js/src/components/contentBlocks/ContentBlocks.js Removes yst-root wrapper around “New” badge label.
packages/js/src/components/contentBlocks/ContentBlock.js Removes yst-root wrapper around upsell badge.
packages/js/src/components/contentAnalysis/WooSeoAnalysisUpsellAd.js Removes yst-root wrapper.
packages/js/src/components/contentAnalysis/SeoAnalysis.js Stops passing legacy tooltip className props into Results.
packages/js/src/components/contentAnalysis/Results.js Adds custom mark button factory using ui-library Button + tooltip + upsell badge.
packages/js/src/components/contentAnalysis/ReadabilityAnalysis.js Stops passing legacy tooltip className prop into Results.
packages/js/src/components/contentAnalysis/PremiumSeoAnalysisUpsellAd.js Replaces outer yst-root div with fragment.
packages/js/src/components/contentAnalysis/InclusiveLanguageAnalysis.js Stops passing legacy tooltip className prop into Results.
packages/js/src/components/WincherSEOPerformanceModal.js Removes yst-root wrapper.
packages/js/src/components/BlackFridayPromotion.js Replaces outer yst-root div with fragment.
packages/analysis-report/src/AnalysisResult.js Replaces legacy icon button components with ui-library Button + heroicons and adds tooltips.
packages/analysis-report/package.json Adds deps required for the new ui-library + heroicons button implementations.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +88 to +98
aria-label={ ariaLabel }
onPointerEnter={ () => setIsTooltipOpen( true ) }
onPointerLeave={ () => setIsTooltipOpen( false ) }
>
<EyeIcon className="yst-w-4 yst-h-4" />
</Button>
{ isTooltipOpen && ! isPressed && (
<Tooltip position="left">
{ ariaLabel }
</Tooltip>
) }
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

The tooltip here is driven by pointer events only (onPointerEnter/onPointerLeave) and renders the Tooltip element directly. The ui-library provides TooltipContainer/TooltipTrigger/TooltipWithContext to handle focus/blur and Escape-to-close behavior, plus aria-describedby linkage. Consider using those helpers (or add equivalent focus/blur + aria-describedby) so the tooltip is accessible via keyboard navigation as well.

Copilot uses AI. Check for mistakes.
Comment on lines +5 to +6
import { EyeIcon } from "@heroicons/react/outline";
import { PencilIcon } from "@heroicons/react/outline";
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

The PR description mentions using @heroicons/react/solid icons, but EyeIcon/PencilIcon are imported from @heroicons/react/outline here. Please align the code with the stated choice (or update the PR description) to avoid confusion during review/QA.

Copilot uses AI. Check for mistakes.
export function InstallationSuccessPage() {
return (
<div className="yst-root yst-my-auto yst-flex yst-flex-col yst-min-h-[84vh] yst-py-12 yst-justify-center">
<div className="yst-my-auto yst-flex yst-flex-col yst-min-h-[84vh] yst-py-12 yst-justify-center">
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

InstallationSuccessPage no longer renders a .yst-root wrapper. Our Tailwind base overrides in css/src/tailwind.css are scoped under .yst-root (e.g., WP focus/inputs resets), so this page may now miss those scoped base styles. Consider restoring the yst-root class on the top-level element or wrapping the page content in an element that provides .yst-root to keep styling consistent with other Yoast admin UIs.

Suggested change
<div className="yst-my-auto yst-flex yst-flex-col yst-min-h-[84vh] yst-py-12 yst-justify-center">
<div className="yst-root yst-my-auto yst-flex yst-flex-col yst-min-h-[84vh] yst-py-12 yst-justify-center">

Copilot uses AI. Check for mistakes.
Comment on lines +46 to +55
onPointerEnter={ () => setIsTooltipOpen( true ) }
onPointerLeave={ () => setIsTooltipOpen( false ) }
>
<EyeIcon className="yst-w-4 yst-h-4" />
</Button>
{ isTooltipOpen && ! isPressed && (
<Tooltip position="left">
{ ariaLabel }
</Tooltip>
) }
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

The new tooltip behavior is implemented via onPointerEnter/onPointerLeave and conditional rendering of <Tooltip>. This bypasses the ui-library’s TooltipContainer/TooltipTrigger/TooltipWithContext helpers (which handle focus/blur, Escape-to-close, and aria-describedby). Consider switching to the tooltip-container components, or at least add onFocus/onBlur + proper aria-describedby wiring so keyboard users get the same tooltip affordance as pointer users.

Copilot uses AI. Check for mistakes.
Comment on lines 2 to 4
import { Badge, Button, Root, Tooltip } from "@yoast/ui-library";
import { EyeIcon } from "@heroicons/react/outline";
import { LockClosedIcon } from "@heroicons/react/solid";
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

The PR description states the new buttons use @heroicons/react/solid, but this implementation imports EyeIcon from @heroicons/react/outline. Either update the implementation to match the intended icon set, or update the PR description/acceptance expectations so they reflect the actual icon variant used.

Copilot uses AI. Check for mistakes.
Comment on lines +68 to +101
const MarkButton = ( {
ariaLabel,
id,
className,
status,
onClick,
isPressed,
} ) => {
return <IconButtonToggle
marksButtonStatus={ status }
className={ className }
onClick={ onClick }
id={ id }
icon="eye"
pressed={ isPressed }
ariaLabel={ ariaLabel }
/>;
const [ isTooltipOpen, setIsTooltipOpen ] = useState( false );

return <Root>
<div className="yst-relative yst-inline-flex">
<Button
variant={ isPressed ? "primary" : "secondary" }
size="small"
className={ classNames( className, "yst-px-2 yst-rounded-lg yst-shadow-none yst-border-0 focus:yst-z-10" ) }
onClick={ onClick }
id={ id }
disabled={ status === "disabled" }
aria-pressed={ isPressed }
aria-label={ ariaLabel }
onPointerEnter={ () => setIsTooltipOpen( true ) }
onPointerLeave={ () => setIsTooltipOpen( false ) }
>
<EyeIcon className="yst-w-4 yst-h-4" />
</Button>
{ isTooltipOpen && ! isPressed && (
<Tooltip position="left">
{ ariaLabel }
</Tooltip>
) }
</div>
</Root>;
};
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

AnalysisResult has Jest snapshot coverage (and ContentAnalysis snapshots include these buttons). Since the mark/edit button markup changed substantially (IconButtonToggle/IconCTAEditButton -> ui-library Button + heroicons), the existing snapshots in packages/analysis-report/tests/__snapshots__ will no longer match. Please update the affected snapshots (run the analysis-report Jest suite with snapshot update) so CI reflects the new intended output.

Copilot uses AI. Check for mistakes.
@JorPV JorPV force-pushed the worktree-replace-content-analysis-buttons branch from dd350ae to 844b8a5 Compare March 12, 2026 08:25
@JorPV
Copy link
Copy Markdown
Contributor Author

JorPV commented Mar 12, 2026

/build-zip

1 similar comment
@enricobattocchi
Copy link
Copy Markdown
Member

/build-zip

@github-actions
Copy link
Copy Markdown

📦 Plugin zip built successfully!

Download it from the workflow run.

@JorPV
Copy link
Copy Markdown
Contributor Author

JorPV commented Mar 12, 2026

/build-zip

@Yoast Yoast deleted a comment from github-actions bot Mar 12, 2026
@JorPV JorPV force-pushed the worktree-replace-content-analysis-buttons branch from a704e3e to ad07334 Compare March 12, 2026 14:43
@github-actions
Copy link
Copy Markdown

📦 Plugin zip built successfully!

Download it from the workflow run.

@JorPV JorPV force-pushed the worktree-replace-content-analysis-buttons branch from 07c5dd5 to 7534f81 Compare March 12, 2026 15:13
@JorPV JorPV force-pushed the yst-root-clean-up-from-plugin branch from 6014ffa to 4238822 Compare March 12, 2026 16:49
@github-actions
Copy link
Copy Markdown

A merge conflict has been detected for the proposed code changes in this PR. Please resolve the conflict by either rebasing the PR or merging in changes from the base branch.

@JorPV JorPV force-pushed the worktree-replace-content-analysis-buttons branch from 7534f81 to f92816d Compare March 12, 2026 16:55
@JorPV JorPV force-pushed the yst-root-clean-up-from-plugin branch from 4238822 to 6972f35 Compare March 12, 2026 19:42
@JorPV JorPV force-pushed the worktree-replace-content-analysis-buttons branch from ad95a65 to e92c533 Compare March 12, 2026 19:42
JorPV and others added 3 commits March 12, 2026 21:12
Replace IconButtonToggle (highlight) and IconCTAEditButton (edit) from
@yoast/components with Button from @yoast/ui-library, using EyeIcon and
PencilIcon from @heroicons/react/solid.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…nalysis buttons

Move EyeIcon and PencilIcon from Button children to the new icon prop,
with sizing handled by CSS class (.yst-button--icon) instead of inline classes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…onent class

The @layer components block strips plain CSS and arbitrary value classes
are not generated by the plugin's Tailwind build. Use standard yst-w-5/yst-h-5
(20px) and yst-w-4/yst-h-4 (16px) utility classes directly in the JSX.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
JorPV and others added 6 commits March 12, 2026 21:12
- Merge duplicate @heroicons/react/outline imports
- Use parameter defaults instead of defaultProps for function components
- Replace arrow functions in JSX props with useCallback handlers
- Update analysis-report test snapshots for new button markup

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rning

- Remove className="yst-root" from analysis-report and search-metadata-previews snapshots
  to match the base branch Root component that no longer outputs yst-root class
- Add eslint-disable complexity for MarkButtonWithUpsell component to stay within
  @yoast/wordpress-seo max-warnings limit

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…dius

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@JorPV JorPV force-pushed the worktree-replace-content-analysis-buttons branch from e92c533 to e518d46 Compare March 12, 2026 20:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog: non-user-facing Needs to be included in the 'Non-userfacing' category in the changelog

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants