Skip to content

fix: render select tooltip as markdown instead of raw HTML - #497

Closed
dungdong-aws wants to merge 1 commit into
Amazon-Q-Developer:mainfrom
dungdong-aws:fix/select-tooltip-markdown
Closed

dungdong-aws wants to merge 1 commit into
Amazon-Q-Developer:mainfrom
dungdong-aws:fix/select-tooltip-markdown

Conversation

@dungdong-aws

Copy link
Copy Markdown
Contributor

Problem

Hovering the model selector in Amazon Q chat showed literal markup instead of
formatted text — e.g. <strong>claude-opus-4.6</strong><br> — rather than a bold
model name with its description underneath.

This affects every IDE host (VS Code, JetBrains, Eclipse, Visual Studio),
because they all load the same bundled chat UI. It is not host-side plugin code.

Root cause

Two parts of mynah-ui disagreed about the tooltip's content format:

  1. The tooltip was authored as raw HTML in
    src/components/form-items/select.ts:

    return `<strong>${selectedOption.label}</strong><br>${selectedOption.description}`;

    and passed to CardBody({ body: content }).

  2. CardBody renders its body through the markdown parser
    (src/components/card/card-body.ts, parseMarkdown(...)).

  3. That parser deliberately escapes raw HTML as XSS hardening —
    src/helper/marked.ts: html: ({ text }) => escapeHTML(text).

So <strong> became &lt;strong&gt; and was displayed verbatim. The existing
marked.spec.ts already encodes this distinction: markdown **bold** renders as
<strong>, while a raw <strong> input is escaped.

Fix

Author the tooltip as markdown. The parser is already configured with
includeLineBreaks: true, so \n becomes a line break:

-      return `<strong>${selectedOption.label}</strong><br>${selectedOption.description}`;
+      return `**${selectedOption.label}**\n${selectedOption.description}`;

Tests

select.spec.ts previously had no tooltip coverage at all, which is why this
regression went unnoticed. This PR adds a Tooltip content suite:

  • renders the tooltip as markdown — asserts a real <strong> element exists
    and that no literal <strong> / <br> appears in the text
  • reflects the currently selected option
  • falls back to the base tooltip prop when the option has no description, and
    renders no bold element in that path

Two details make these tests meaningful rather than vacuous:

  • they call the real configureMarked(), so the HTML-escaping renderer is
    active. Without it the tests would pass against the buggy code too.
  • they mock Overlay (whose real responsibility is positioning, which is noise
    under jsdom) to capture the content that would have been displayed.

Relationship to #489

#489 proposes the same one-line change. This PR is equivalent on
select.ts (byte-identical code line) and covers the same three test cases,
with one extra assertion in the fallback case.

The difference: #489 also modifies
ui-tests/__test__/flows/quick-action-commands-header.ts — a Boolean()
coercion in a Playwright helper for the quick-picks header, unrelated to the
tooltip (its own commit is labelled chore:). This PR leaves that out to keep
the change scoped to the bug.

Happy to close this in favour of #489 if the maintainers prefer — the goal is the
fix landing, not this particular PR.

Verification

  • CI on this PR runs lint, unit tests and e2e-linux.
  • ⚠️ Local test run pending — the tooltip suite has not yet been executed in
    my environment, so CI is the first execution of these tests. Will follow up
    with results and before/after screenshots.

Follow-up considered and left out

Callers currently send description: model.description ?? ''. An empty string is
not null, so the tooltip still fires with an empty second line. Guarding it:

if (selectedOption?.description != null && selectedOption.description.trim() !== '') {

That is a behavioural change rather than a rendering fix, so it is
deliberately out of scope here (#489 omits it too). Happy to add it if
maintainers want it in the same change.


Internal tracking: P447078389

The select tooltip was authored as raw HTML:

    `<strong>${label}</strong><br>${description}`

That string is passed to CardBody, which renders its body through the
markdown parser. The parser's `html` renderer deliberately escapes raw
HTML as XSS hardening (src/helper/marked.ts), so the tags reached the
user as literal text instead of a bold label and a description.

Author the tooltip as markdown instead. The parser is already configured
with `includeLineBreaks`, so a newline becomes a line break.

Also adds a `Tooltip content` suite to select.spec.ts, which previously
had no tooltip coverage at all. The tests call the real configureMarked()
so the HTML-escaping renderer is active -- without it a test would pass
against the buggy code too.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant