From 4aa26d5e66f4448c8ea8536d192283af78bbe6bc Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Sun, 18 Oct 2026 02:21:15 -0700 Subject: [PATCH 1/8] Name Action.ShowCard as the exception in Adaptive Card hack comments The comments named Action.ShowUrl, but the code exempts buttons with aria-expanded, which is Action.ShowCard. --- .../AdaptiveCardHacks/useActionShouldBePushButtonModEffect.ts | 2 +- .../Attachment/AdaptiveCardHacks/useDisabledModEffect.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardHacks/useActionShouldBePushButtonModEffect.ts b/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardHacks/useActionShouldBePushButtonModEffect.ts index 6a662d04d4..1583c6f019 100644 --- a/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardHacks/useActionShouldBePushButtonModEffect.ts +++ b/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardHacks/useActionShouldBePushButtonModEffect.ts @@ -20,7 +20,7 @@ import type { UndoFunction } from '../../DOMManipulationWithUndo/types/UndoFunct * * Since action buttons are button, the intuitive way to indicate selection of a button is marking it as pressed. * - * One exception is the `Action.ShowUrl` action. This button represents expand/collapse header of an accordion. + * One exception is the `Action.ShowCard` action. This button represents expand/collapse header of an accordion. * Thus, their state is indicated by `aria-expanded`, instead of `aria-pressed`. * However, we still need to remove other unnecessary ARIA fields. */ diff --git a/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardHacks/useDisabledModEffect.ts b/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardHacks/useDisabledModEffect.ts index 0fb043c456..06b7451578 100644 --- a/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardHacks/useDisabledModEffect.ts +++ b/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardHacks/useDisabledModEffect.ts @@ -20,7 +20,7 @@ type InputElementType = HTMLButtonElement | HTMLInputElement | HTMLSelectElement /** * Accessibility: Form fields in Adaptive Cards need to be disabled to reduce confusion for screen reader users. * - * One exception is the `Action.ShowUrl`, this is because this action is expand/collapse of an accordion control. + * One exception is the `Action.ShowCard`, this is because this action is expand/collapse of an accordion control. * Similar to `
`/``, accordion must not allowed to be disabled. */ export default function useDisabledModEffect( From e87d09b5e97d87db711298beb0bea9d84d34a283 Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Sun, 18 Oct 2026 02:21:20 -0700 Subject: [PATCH 2/8] Announce card action buttons as buttons, describe pressed actions as Selected Card action buttons had aria-pressed, so screen readers announced them as toggle buttons that never turn off (#5716, #5719, #5745, #5750). They are now plain buttons; pressed actions are described as "Selected" via aria-describedby, which keeps the choice announced (#3622), and is styled via the adaptive-card-renderer__action--selected class instead of [aria-pressed='true'] in the default and Fluent themes. --- CHANGELOG.md | 2 + .../adaptiveCard/ariaPushed.html | 65 ++----- .../hack.actionShouldBePushButtonMod.html | 24 ++- .../adaptiveCard/selectedAction.copilot.html | 9 + .../selectedAction.copilot.html.snap-1.png | Bin 0 -> 11816 bytes .../adaptiveCard/selectedAction.fluent.html | 9 + .../selectedAction.fluent.html.snap-1.png | Bin 0 -> 12622 bytes .../adaptiveCard/selectedAction.html | 167 ++++++++++++++++++ .../selectedAction.html.snap-1.png | Bin 0 -> 11371 bytes .../heroCard.pushButton.focusVisible.html | 8 +- packages/api/src/localization/en-US.json | 2 + .../AdaptiveCardsStyleOptions.ts | 4 +- .../useActionShouldBePushButtonModEffect.ts | 36 ++-- .../AdaptiveCardRenderer.module.css | 5 +- .../Attachment/AdaptiveCardRenderer.tsx | 33 +++- .../durableAddClassWithUndo.ts | 16 +- .../Styles/StyleSet/AdaptiveCardRenderer.ts | 2 +- .../activity/PartGroupingDecorator.module.css | 7 +- 18 files changed, 289 insertions(+), 100 deletions(-) create mode 100644 __tests__/html2/accessibility/adaptiveCard/selectedAction.copilot.html create mode 100644 __tests__/html2/accessibility/adaptiveCard/selectedAction.copilot.html.snap-1.png create mode 100644 __tests__/html2/accessibility/adaptiveCard/selectedAction.fluent.html create mode 100644 __tests__/html2/accessibility/adaptiveCard/selectedAction.fluent.html.snap-1.png create mode 100644 __tests__/html2/accessibility/adaptiveCard/selectedAction.html create mode 100644 __tests__/html2/accessibility/adaptiveCard/selectedAction.html.snap-1.png diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ea94b2678..4085e5d006 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ Legends: - 💥 `useSendMessage`: `init.attachments[].thumbnailURL` must be data URI, otherwise will be ignored, in PR [#5871](https://github.com/microsoft/BotFramework-WebChat/pull/5871), by [@compulim](https://github.com/compulim) - 👷🏻 Visual regression tests now use 5 consecutive screenshots for stability indication, up from 2, in PR [#5871](https://github.com/microsoft/BotFramework-WebChat/pull/5871), by [@compulim](https://github.com/compulim) +- 💥 Card action buttons the user pressed are styled with the `adaptive-card-renderer__action--selected` class instead of `[aria-pressed='true']`: host CSS that targets `.ac-pushButton[aria-pressed='true']` should target `.ac-pushButton.adaptive-card-renderer__action--selected` instead, in PR [#XXXX](https://github.com/microsoft/BotFramework-WebChat/pull/XXXX), by [@OEvgeny](https://github.com/OEvgeny) ### Removed @@ -63,6 +64,7 @@ Legends: - Fixed screen readers announcing a single audio, video, or animation in a card as a list item, such as "1 of 1", fixes [#5722](https://github.com/microsoft/BotFramework-WebChat/issues/5722), in PR [#5903](https://github.com/microsoft/BotFramework-WebChat/pull/5903), by [@OEvgeny](https://github.com/OEvgeny) - Fixed video and animation cards disappearing in production builds when the video URL is relative or invalid, in PR [#5889](https://github.com/microsoft/BotFramework-WebChat/pull/5889), by [@OEvgeny](https://github.com/OEvgeny) - Fixed timestamps always using the 12-hour clock, such as "4:41 PM" instead of "16:41" in German, in PR [#5920](https://github.com/microsoft/BotFramework-WebChat/pull/5920), by [@OEvgeny](https://github.com/OEvgeny) +- Fixed card action buttons, such as Adaptive Card actions and hero card buttons, being announced as toggle buttons that could not be turned off: they are now buttons, and pressed actions are described as "Selected", fixes [#5716](https://github.com/microsoft/BotFramework-WebChat/issues/5716), [#5719](https://github.com/microsoft/BotFramework-WebChat/issues/5719), [#5745](https://github.com/microsoft/BotFramework-WebChat/issues/5745), and [#5750](https://github.com/microsoft/BotFramework-WebChat/issues/5750), in PR [#XXXX](https://github.com/microsoft/BotFramework-WebChat/pull/XXXX), by [@OEvgeny](https://github.com/OEvgeny) ## [4.19.2] - 2026-10-08 diff --git a/__tests__/html2/accessibility/adaptiveCard/ariaPushed.html b/__tests__/html2/accessibility/adaptiveCard/ariaPushed.html index 27bf6b2477..e18a75aab8 100644 --- a/__tests__/html2/accessibility/adaptiveCard/ariaPushed.html +++ b/__tests__/html2/accessibility/adaptiveCard/ariaPushed.html @@ -1,4 +1,4 @@ - + @@ -9,29 +9,19 @@
diff --git a/__tests__/html2/accessibility/adaptiveCard/hack.actionShouldBePushButtonMod.html b/__tests__/html2/accessibility/adaptiveCard/hack.actionShouldBePushButtonMod.html index af4732612a..1f15b2d1f3 100644 --- a/__tests__/html2/accessibility/adaptiveCard/hack.actionShouldBePushButtonMod.html +++ b/__tests__/html2/accessibility/adaptiveCard/hack.actionShouldBePushButtonMod.html @@ -9,6 +9,10 @@
diff --git a/__tests__/html2/accessibility/adaptiveCard/selectedAction.copilot.html b/__tests__/html2/accessibility/adaptiveCard/selectedAction.copilot.html new file mode 100644 index 0000000000..56ff19130f --- /dev/null +++ b/__tests__/html2/accessibility/adaptiveCard/selectedAction.copilot.html @@ -0,0 +1,9 @@ + + + + + + + diff --git a/__tests__/html2/accessibility/adaptiveCard/selectedAction.copilot.html.snap-1.png b/__tests__/html2/accessibility/adaptiveCard/selectedAction.copilot.html.snap-1.png new file mode 100644 index 0000000000000000000000000000000000000000..ee8eca85672393aa07b5e6bdaf84fb27ec26abc9 GIT binary patch literal 11816 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 + + + + + + diff --git a/__tests__/html2/accessibility/adaptiveCard/selectedAction.fluent.html.snap-1.png b/__tests__/html2/accessibility/adaptiveCard/selectedAction.fluent.html.snap-1.png new file mode 100644 index 0000000000000000000000000000000000000000..95f390d541f2565ba57071a391052b1f90f68fb8 GIT binary patch literal 12622 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 WlVRxUfjn@9;FY|pT=9!H0sjj)r4%^; literal 0 HcmV?d00001 diff --git a/__tests__/html2/accessibility/adaptiveCard/selectedAction.html b/__tests__/html2/accessibility/adaptiveCard/selectedAction.html new file mode 100644 index 0000000000..5a554f8a4a --- /dev/null +++ b/__tests__/html2/accessibility/adaptiveCard/selectedAction.html @@ -0,0 +1,167 @@ + + + + + + +
+ + + + diff --git a/__tests__/html2/accessibility/adaptiveCard/selectedAction.html.snap-1.png b/__tests__/html2/accessibility/adaptiveCard/selectedAction.html.snap-1.png new file mode 100644 index 0000000000000000000000000000000000000000..1655766080d698d57f59c0aa595c4368cbef228d GIT binary patch literal 11371 zcmeHtc|4SF+rH{6;fs`|FjTUWvS&?pS;CBoEFsxp0HiI*v2?sh$QM4I2#w1qGd!rm7(Y z#RYo`ii@FFE&{J8`oT6SD6UdysVam0GS+a^&mc>aU0al4q3>e&V~hs99=;4WDSB08 zJZNf~I*`vPXAIXux5|D_rlY5WR||Xby9`Sp4Qrf7JvlvC3>cMD6Xu(>pcopU!E? zQ=f*UU|Yv60@jgK2LYA%AeOH|V&dW;im#g<6z%WkC|;<$Q{3m4q4>hcLD7GOp5oPC zR21T2mqKrTyU_mOKX3o1EdSXK|AE1O*x{eBBF&Y!4CMkh>zFT)O=T8 zUw>(FJ~=ftb!foAz(849nM@|rYo{(QE;ckYARwi(k2ong^ubOa*$NZMvn3K9vb+B} z39Ici#XtEhd{e^yX(F#~SXh{8y{p2@pI6I0+-MjW4z{SF8GLAk7e&4rNOQ$CqWUgT(R&Yu1)c1xsjAAfKPe-px7nGNfCE7Y!hR+< zVmA0hS7`P%9;EwPz74Gqc<8Xe2MhS z(E_a$Gf%Au8fI_S7U=5gsy{tG(>Kc%Q^BMIwG7&WVa-!^9?tqL#De5}`u861lV&Ri zrt53nW?MDlIS25!Ip*{Q!sdoUk5=K?5`?jz@7}+cTaprOJbOFFqu{gMnH; zoQU@7WQKw(%wC@z?@fkhXU{^Q=FA`vuJ8$KY|CuOIj)5iuS70R$fuhwRXW`akK0jH zJTFNO3<`<|$?dPz3^|@R`I5$Ql3BR<7SE;LlZ_^Q<*yzK>g8=m%jw8!om4SYmW87u zBJZ}C*fuHT{6vE*s9?VQHhx1{g6e1wYq?iz31|yo9cI9TzlfHWR^#f~!EAg?OfRxt zG3dDXMyj-1R@YbcCQk3I-@ED!xL|Yd5REi#=p8VeP@n_LdZKQ zmcgr&$Wp^cDr({(2OWgmWVZW_W5VhRV~|o~ho#cWRz!Ffffm$594|iskimEN?n>(( z5$iTqoZwUJlEjUm^cFq1m&aWfX;y*Hxv;a6A5U;c@a52`g%g1K4Ii7-yuy^3czu6M zEql@FgMhN$(KYa$Ao3BOE9A6_Q!|PfeVwnXtE(}-Sa0C;XlJj?we8FYv~TIZ%7YPg zT*=tL4L^m3IwsXQpw&D38ax(Ek&cB3zH@wug!5Egc~))~JZw4Lt+nR_O!fDT99gyN zDhG(~D~mme($nrLgD&7W0h1#AYzw$vCIF?DtuFRIO94tpdvx{DZDwV6zkmQG^5Mes zdROx*>j=dJL0NC-zp1Gws%_ufrL%~b`h5-$4~Nacs_m!*v3?me0McJKLaVGgE;EC) zZw@Gf`{gDm6B5lyD;rsvPHVd9Qo7f((d!z8v2|^y+kFa7wPn(O*4PiZT3l;z+kIvD zwitiPlc51wz?9C7 z4v`%~ehn;z;4i=R<9b&5Ztj6_K;vz}ZQQqo+=Z`lW^%q8W!wdcAPzP^w$m7jplKLV zIs9@gyY%46ivN#hAscJ!-V{+1%D=HKr=5HC*R&Yq-E!1NZj0jdFWv;|*OhuX z%Kz%Igp+o*Q%hV7!G1Z!Qdeh86?|!^1!2UQ)-2&RGu@-8O&seOEqo%W=GzzC*^O`( zL}flkgDt(T4nbho^--x|`snNW9he>T&5cBGTNm1D#Nk#%8lFktf)KhmJ=5dbyO>du z`AN2VLlIIw4Un6xuUBJs*oed?T3-nQS4oV^09g;^J8gI^B}09Vm1wL7jCFv^TLFre zDV1pvwB5r8p(frh7JrA>$Ebo;47j#VNphZxnlPTd+s3zZR_ocWPNpL~4vd3VFa=<{ zk#!mGm0@MP^_Z}XZTN!s@d2qax8h!zJr~8p6TT*D-kmOud4#dPn<&H)A1~e4^?HJ&M(HHMf+L#9Q!y zD|7n%VVvDcqyrmW$dw6G>HZ@CHQ)J~Uj83Tc{Awl0*E&P=ELNOO$F}HOSz|F;<4PuSwB(BPo zYWum{JBkM#d&8u`6@b(j>LD|hSRV%!*Ss1a;F{_OwMtbydc7LkLv*RL5pz15ZSm-N zhNFM!^vb;XoLx~-v8ShpUYqNz4S%Mh99kMW3+eg!^IcrreqblHHbbGhrl#hDvxr9- zE|h@WTT~OF`QJ{!WubF(8iQ{}i|)6%JZ+E9&`?vOq@+ALIgz8#j`|;|w_Kxpq3wHt zY4{k0HZ$GPMZTN=Q0j4&GK>GW7w~^Qnwv0EMWv*qT$-CsJZH^)mKhPVP$fbi>eah5 zka4FIO!@B}?X}Y;!ky?FZ~Zja8*=yId}3ZJV%0xdd|lw?XPk_cvLaQseFN_u6mC(W zQMS%0+0Ezf=~rn1tbdZ;Um88NFPs7oN5+P?6~-K32^AL~$0fd@~Rmz}+|?r!APS%!;j`(;fGn4TBrJWQMU$kB5ed z>68#U;p?24vQ}!lQ6U+_Qj$W4&A~xPALPZbOU)s;?9)NFs+#faEA;$36Cy~k$qIoz z2;o$t)q>b_V)RC@g>M`?%}jA^`Kd6Ak^I@+sk zn_H(+-G}U=@~(}7l5Wk=Yu7F{U4yNX68ES+znXrwLw*ttUDrLGI_=;?i^CZZ9!5kO z)AMa)Zc7@~naxN-0xdn1T6o8~9-)18h_iJj>%NVPajOnl;MMLZ|IqQukKMv~>fW5e zy}ngKY`NfHpZ5%36xzyoMUHVyBfgix__9o|VX7=p^~c7(PphwT@T6)-Q!6}1ZZ6Ce z$TA1{ON(-)CwVONhr6A#$$18k_b*kv7g`l-$4*W4p_*OWdvVd_mb19c!psL+=c&
9Dl0CG5J?~Kn<^efJ3V6GGC!>QIYLgkJfBr}* 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 expect(placesToBuyButton.getAttribute('aria-pressed')).toBe('true')); + // THEN: The "Places To Buy" button should be selected and keep the focus. + await waitFor(async () => + expect((await testHelpers.getAccessibilityNode(placesToBuyButton)).description?.value).toBe('Selected') + ); expect(document.activeElement).toBe(placesToBuyButton); - // THEN: The white inner band should separate the black ring from the pressed button (blue). + // THEN: The white inner band should separate the black ring from the selected button (blue). await pageConditions.scrollToBottomCompleted(); await host.snapshot('local'); }); diff --git a/packages/api/src/localization/en-US.json b/packages/api/src/localization/en-US.json index 4a978b61e5..de235be977 100644 --- a/packages/api/src/localization/en-US.json +++ b/packages/api/src/localization/en-US.json @@ -47,6 +47,8 @@ "ACTIVITY_STATUS_TIMESTAMP_ONE_MINUTE_AGO": "A minute ago", "ACTIVITY_STATUS_TIMESTAMP_TODAY": "Today", "ACTIVITY_STATUS_TIMESTAMP_YESTERDAY": "Yesterday", + "ADAPTIVE_CARD_ACTION_SELECTED_ALT": "Selected", + "_ADAPTIVE_CARD_ACTION_SELECTED_ALT.comment": "This is for screen reader only. It is the description of a button in a card after the user pressed it, e.g. \"Snooze, button, Selected\".", "ADAPTIVE_CARD_ERROR_BOX_TITLE_PARSE": "Adaptive Card parse error", "ADAPTIVE_CARD_ERROR_BOX_TITLE_RENDER": "Adaptive Card render error", "ANIMATION_PAUSE_BUTTON_ALT": "Pause animation", diff --git a/packages/bundle/src/adaptiveCards/AdaptiveCardsStyleOptions.ts b/packages/bundle/src/adaptiveCards/AdaptiveCardsStyleOptions.ts index 4996648031..4a7f195865 100644 --- a/packages/bundle/src/adaptiveCards/AdaptiveCardsStyleOptions.ts +++ b/packages/bundle/src/adaptiveCards/AdaptiveCardsStyleOptions.ts @@ -11,12 +11,12 @@ type StrictAdaptiveCardsStyleOptions = { cardEmphasisBackgroundColor: string | undefined; /** - * Adaptive Cards: background color of Adaptive Cards button with status of 'aria-pressed' + * Adaptive Cards: background color of the selected Adaptive Cards button, i.e. the action the user has performed */ cardPushButtonBackgroundColor: string | undefined; /** - * Adaptive Cards: text color of Adaptive Cards button with status of 'aria-pressed', and the inner band of the keyboard focus indicator of Adaptive Cards buttons + * Adaptive Cards: text color of the selected Adaptive Cards button, i.e. the action the user has performed, and the inner band of the keyboard focus indicator of Adaptive Cards buttons */ cardPushButtonTextColor: string | undefined; diff --git a/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardHacks/useActionShouldBePushButtonModEffect.ts b/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardHacks/useActionShouldBePushButtonModEffect.ts index 1583c6f019..b41f064a68 100644 --- a/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardHacks/useActionShouldBePushButtonModEffect.ts +++ b/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardHacks/useActionShouldBePushButtonModEffect.ts @@ -13,43 +13,44 @@ import type { AdaptiveCard, CardObject } from 'adaptivecards'; import type { UndoFunction } from '../../DOMManipulationWithUndo/types/UndoFunction'; /** - * Accessibility: Action in ActionSet/CardElement should be push button. + * Accessibility: Action in ActionSet/CardElement should be push button, i.e. a plain command button. * * Pressing the action button is a decision-making process. The decision made by the end-user need to be read by the screen reader. * Thus, we need to indicate what decision the end-user made. * - * Since action buttons are button, the intuitive way to indicate selection of a button is marking it as pressed. + * Action buttons are not toggle buttons: pressing a selected action again does not unselect it. + * Thus, instead of `aria-pressed`, the selected action is described by the element of `descriptionId` (e.g. "Selected"), + * and styled by `selectedClassName`. * * One exception is the `Action.ShowCard` action. This button represents expand/collapse header of an accordion. - * Thus, their state is indicated by `aria-expanded`, instead of `aria-pressed`. + * Thus, their state is indicated by `aria-expanded` and they are never selected. * However, we still need to remove other unnecessary ARIA fields. */ export default function useActionShouldBePushButtonModEffect( adaptiveCard: AdaptiveCard -): readonly [(cardElement: HTMLElement, actionPerformedClassName?: string | undefined) => void, () => void] { +): readonly [(cardElement: HTMLElement, selectedClassName: string, descriptionId: string) => void, () => void] { const prevAdaptiveCard = usePrevious(adaptiveCard); const pushedCardObjectsRef = useRef>(new Set()); prevAdaptiveCard === adaptiveCard || pushedCardObjectsRef.current.clear(); const modder = useMemo( - () => (adaptiveCard: AdaptiveCard, cardElement: HTMLElement, actionPerformedClassName?: string | undefined) => { + () => (adaptiveCard: AdaptiveCard, cardElement: HTMLElement, selectedClassName: string, descriptionId: string) => { const undoStack: UndoFunction[] = []; + const markAsSelected = (actionElement: HTMLElement) => + undoStack.push( + durableAddClassWithUndo(actionElement, selectedClassName), + setOrRemoveAttributeIfFalseWithUndo(actionElement, 'aria-describedby', descriptionId) + ); + Array.from(cardElement.querySelectorAll('button.ac-pushButton') as NodeListOf).forEach( actionElement => { const cardObject = findDOMNodeOwner(adaptiveCard, actionElement); - if (!actionElement.hasAttribute('aria-expanded')) { - if (pushedCardObjectsRef.current.has(cardObject)) { - actionPerformedClassName && - undoStack.push(durableAddClassWithUndo(actionElement, actionPerformedClassName)); - - undoStack.push(setOrRemoveAttributeIfFalseWithUndo(actionElement, 'aria-pressed', 'true')); - } else { - undoStack.push(setOrRemoveAttributeIfFalseWithUndo(actionElement, 'aria-pressed', 'false')); - } - } + !actionElement.hasAttribute('aria-expanded') && + pushedCardObjectsRef.current.has(cardObject) && + markAsSelected(actionElement); undoStack.push( setOrRemoveAttributeIfFalseWithUndo(actionElement, 'aria-posinset', false), @@ -85,10 +86,7 @@ export default function useActionShouldBePushButtonModEffect( return; } - actionPerformedClassName && - undoStack.push(durableAddClassWithUndo(actionElement, actionPerformedClassName)); - - undoStack.push(setOrRemoveAttributeIfFalseWithUndo(actionElement, 'aria-pressed', 'true')); + markAsSelected(actionElement); cardObject && pushedCardObjectsRef.current.add(cardObject); }, diff --git a/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardRenderer.module.css b/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardRenderer.module.css index 3986724a34..56de9e2419 100644 --- a/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardRenderer.module.css +++ b/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardRenderer.module.css @@ -28,7 +28,7 @@ } /* Two-tone focus indicator, drawn inside the button as the action set clips anything outside of the button. */ - /* The outer ring is visible against the card, the inner band separates it from the button, including when pressed. */ + /* The outer ring is visible against the card, the inner band separates it from the button, including when selected. */ :global(.ac-pushButton:focus-visible) { /* The inset shadow starts inside the 1px border, so the band is 2px wide inside the outer ring. */ box-shadow: inset 0 0 0 calc(var(--webchat__border-width--transcript-visual-keyboard-indicator) + 1px) @@ -77,7 +77,8 @@ color: #4f4f4f; } - :global(.ac-pushButton[aria-pressed='true']) { + /* The action the user has performed, its "Selected" state is exposed via `aria-describedby`. */ + :global(.ac-pushButton).adaptive-card-renderer__action--selected { background-color: var(--webchat__background--card-push-button, #0063b1); border-color: var(--webchat__background--card-push-button, #0063b1); color: var(--webchat__color--card-push-button, white); diff --git a/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardRenderer.tsx b/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardRenderer.tsx index 12715f7c5f..f9ee5baa27 100644 --- a/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardRenderer.tsx +++ b/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardRenderer.tsx @@ -6,7 +6,9 @@ import { type Action as AdaptiveCardAction, type OpenUrlAction, type SubmitActio import { ErrorBoxPolymiddlewareProxy } from 'botframework-webchat-api/middleware.js'; import { getTabIndex, hooks } from 'botframework-webchat-component'; import { type DirectLineCardAction } from 'botframework-webchat-core'; +import cx from 'classnames'; import React, { + Fragment, memo, useCallback, useEffect, @@ -21,6 +23,7 @@ import { any, boolean, object, optional, pipe, readonly, string, type InferInput import useAdaptiveCardsHostConfig from '../hooks/useAdaptiveCardsHostConfig'; import useAdaptiveCardsPackage from '../hooks/useAdaptiveCardsPackage'; +import useUniqueId from '../hooks/internal/useUniqueId'; import { BotFrameworkCardAction } from './AdaptiveCardBuilder'; import useValueRef from './AdaptiveCardHacks/private/useValueRef'; import useActionShouldBePushButtonModEffect from './AdaptiveCardHacks/useActionShouldBePushButtonModEffect'; @@ -66,6 +69,7 @@ function AdaptiveCardRenderer(props: AdaptiveCardRendererProps) { const performCardAction = usePerformCardAction(); const renderMarkdownAsHTML = useRenderMarkdownAsHTML('adaptive cards'); const scrollToEnd = useScrollToEnd(); + const selectedDescriptionId = useUniqueId('webchat__adaptive-card-renderer__selected-description'); const classNames = useStyles(styles); const disabled = uiState === 'disabled' || disabledFromProps; @@ -258,7 +262,11 @@ function AdaptiveCardRenderer(props: AdaptiveCardRendererProps) { // This is because we have undoed mods when we call the `useXXXModEffect` hook. useLayoutEffect(() => { if (element) { - applyActionShouldBePushButtonMod(element, actionPerformedClassName); + applyActionShouldBePushButtonMod( + element, + cx(classNames['adaptive-card-renderer__action--selected'], actionPerformedClassName), + selectedDescriptionId + ); applyActiveElementMod(element); applyDisabledMod(element, disabled); applyImageAltTextMod(element); @@ -273,8 +281,10 @@ function AdaptiveCardRenderer(props: AdaptiveCardRendererProps) { applyImageAltTextMod, applyPersistValuesMod, applyRoleMod, + classNames, disabled, - element + element, + selectedDescriptionId ]); errors?.length && console.warn('botframework-webchat: Failed to render Adaptive Cards.', errors); @@ -282,12 +292,19 @@ function AdaptiveCardRenderer(props: AdaptiveCardRendererProps) { return errors?.length ? ( ) : ( -
} - onKeyPress={handleClickAndKeyPressForTapAction as KeyboardEventHandler} - ref={contentRef} - /> + +
} + onKeyPress={handleClickAndKeyPressForTapAction as KeyboardEventHandler} + ref={contentRef} + /> + {/* `id` is required for `aria-describedby` of the selected action */} + {/* eslint-disable-next-line react/forbid-dom-props */} + + ); } diff --git a/packages/bundle/src/adaptiveCards/DOMManipulationWithUndo/durableAddClassWithUndo.ts b/packages/bundle/src/adaptiveCards/DOMManipulationWithUndo/durableAddClassWithUndo.ts index b07ccad5c4..c57d392bd9 100644 --- a/packages/bundle/src/adaptiveCards/DOMManipulationWithUndo/durableAddClassWithUndo.ts +++ b/packages/bundle/src/adaptiveCards/DOMManipulationWithUndo/durableAddClassWithUndo.ts @@ -4,21 +4,25 @@ import noOp from './private/noOp'; import type { UndoFunction } from './types/UndoFunction'; /** - * Adds a class to the `HTMLElement` and re-add on mutations. + * Adds one or more space-separated classes to the `HTMLElement` and re-add on mutations. * * @returns {function} A function, when called, will restore to previous state. */ export default function durableAddClassWithUndo(element: HTMLElement | undefined, className: string): UndoFunction { - if (element) { - addClass(element, className); + const classNames = className.split(/\s+/u).filter(Boolean); - // After we add the class, keep observing the element to make sure the class is not removed. - const observer = new MutationObserver(() => addClass(element, className)); + if (element && classNames.length) { + const addClasses = () => classNames.forEach(name => addClass(element, name)); + + addClasses(); + + // After we add the classes, keep observing the element to make sure the classes are not removed. + const observer = new MutationObserver(addClasses); observer.observe(element, { attributes: true, attributeFilter: ['class'] }); return () => { - element.classList.remove(className); + element.classList.remove(...classNames); observer.disconnect(); }; diff --git a/packages/bundle/src/adaptiveCards/Styles/StyleSet/AdaptiveCardRenderer.ts b/packages/bundle/src/adaptiveCards/Styles/StyleSet/AdaptiveCardRenderer.ts index 9c6fd5d2e3..f979bb6d4e 100644 --- a/packages/bundle/src/adaptiveCards/Styles/StyleSet/AdaptiveCardRenderer.ts +++ b/packages/bundle/src/adaptiveCards/Styles/StyleSet/AdaptiveCardRenderer.ts @@ -75,7 +75,7 @@ export default function ({ color: '#4F4F4F' }, - '& .ac-pushButton[aria-pressed="true"]': { + '& .ac-pushButton.adaptive-card-renderer__action--selected': { backgroundColor: cardPushButtonBackgroundColor, borderColor: cardPushButtonBackgroundColor, color: cardPushButtonTextColor, diff --git a/packages/fluent-theme/src/components/activity/PartGroupingDecorator.module.css b/packages/fluent-theme/src/components/activity/PartGroupingDecorator.module.css index 3504c33af8..eb814dfc74 100644 --- a/packages/fluent-theme/src/components/activity/PartGroupingDecorator.module.css +++ b/packages/fluent-theme/src/components/activity/PartGroupingDecorator.module.css @@ -24,8 +24,7 @@ --webchat-bubble-minHeight: var(--bubble-minHeight, 36px); --webchat-externalLink-mask: var( --externalLink-mask, - var(--webchat__icon-url--external-link) center center / - 10px 10px + var(--webchat__icon-url--external-link) center center / 10px 10px ); --webchat-externalLink-maxWidth: var(--externalLink-maxWidth, 204px); @@ -676,7 +675,7 @@ } :global(.ac-pushButton:active), - :global(.ac-pushButton[aria-pressed='true']) { + :global(.ac-pushButton.adaptive-card-renderer__action--selected) { background-color: var(--webchat-colorNeutralBackground1Pressed); border-color: var(--webchat-colorNeutralStroke1Pressed); color: var(--webchat-colorNeutralForeground1Pressed); @@ -703,7 +702,7 @@ } :global(.ac-pushButton.primary:active), - :global(.ac-pushButton.primary[aria-pressed='true']) { + :global(.ac-pushButton.primary.adaptive-card-renderer__action--selected) { background-color: var(--webchat-colorBrandBackgroundPressed); border-color: transparent; color: var(--webchat-colorNeutralForegroundOnBrand); From a8d85477591ee5e2e2f5e50af4961b4bf8976b55 Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Sun, 18 Oct 2026 02:51:27 -0700 Subject: [PATCH 3/8] Add PR number to changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4085e5d006..464d4aed73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,7 +30,7 @@ Legends: - 💥 `useSendMessage`: `init.attachments[].thumbnailURL` must be data URI, otherwise will be ignored, in PR [#5871](https://github.com/microsoft/BotFramework-WebChat/pull/5871), by [@compulim](https://github.com/compulim) - 👷🏻 Visual regression tests now use 5 consecutive screenshots for stability indication, up from 2, in PR [#5871](https://github.com/microsoft/BotFramework-WebChat/pull/5871), by [@compulim](https://github.com/compulim) -- 💥 Card action buttons the user pressed are styled with the `adaptive-card-renderer__action--selected` class instead of `[aria-pressed='true']`: host CSS that targets `.ac-pushButton[aria-pressed='true']` should target `.ac-pushButton.adaptive-card-renderer__action--selected` instead, in PR [#XXXX](https://github.com/microsoft/BotFramework-WebChat/pull/XXXX), by [@OEvgeny](https://github.com/OEvgeny) +- 💥 Card action buttons the user pressed are styled with the `adaptive-card-renderer__action--selected` class instead of `[aria-pressed='true']`: host CSS that targets `.ac-pushButton[aria-pressed='true']` should target `.ac-pushButton.adaptive-card-renderer__action--selected` instead, in PR [#5900](https://github.com/microsoft/BotFramework-WebChat/pull/5900), by [@OEvgeny](https://github.com/OEvgeny) ### Removed @@ -64,7 +64,7 @@ Legends: - Fixed screen readers announcing a single audio, video, or animation in a card as a list item, such as "1 of 1", fixes [#5722](https://github.com/microsoft/BotFramework-WebChat/issues/5722), in PR [#5903](https://github.com/microsoft/BotFramework-WebChat/pull/5903), by [@OEvgeny](https://github.com/OEvgeny) - Fixed video and animation cards disappearing in production builds when the video URL is relative or invalid, in PR [#5889](https://github.com/microsoft/BotFramework-WebChat/pull/5889), by [@OEvgeny](https://github.com/OEvgeny) - Fixed timestamps always using the 12-hour clock, such as "4:41 PM" instead of "16:41" in German, in PR [#5920](https://github.com/microsoft/BotFramework-WebChat/pull/5920), by [@OEvgeny](https://github.com/OEvgeny) -- Fixed card action buttons, such as Adaptive Card actions and hero card buttons, being announced as toggle buttons that could not be turned off: they are now buttons, and pressed actions are described as "Selected", fixes [#5716](https://github.com/microsoft/BotFramework-WebChat/issues/5716), [#5719](https://github.com/microsoft/BotFramework-WebChat/issues/5719), [#5745](https://github.com/microsoft/BotFramework-WebChat/issues/5745), and [#5750](https://github.com/microsoft/BotFramework-WebChat/issues/5750), in PR [#XXXX](https://github.com/microsoft/BotFramework-WebChat/pull/XXXX), by [@OEvgeny](https://github.com/OEvgeny) +- Fixed card action buttons, such as Adaptive Card actions and hero card buttons, being announced as toggle buttons that could not be turned off: they are now buttons, and pressed actions are described as "Selected", fixes [#5716](https://github.com/microsoft/BotFramework-WebChat/issues/5716), [#5719](https://github.com/microsoft/BotFramework-WebChat/issues/5719), [#5745](https://github.com/microsoft/BotFramework-WebChat/issues/5745), and [#5750](https://github.com/microsoft/BotFramework-WebChat/issues/5750), in PR [#5900](https://github.com/microsoft/BotFramework-WebChat/pull/5900), by [@OEvgeny](https://github.com/OEvgeny) ## [4.19.2] - 2026-10-08 From e239f518ab27f2272b2731a286c8d4b35f39b8af Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Mon, 19 Oct 2026 01:17:35 -0700 Subject: [PATCH 4/8] Select card actions only after Adaptive Cards performed them An Action.Submit whose required inputs fail validation is not executed by Adaptive Cards, but the capture-phase click handler still marked it as selected. Mark the action from onExecuteAction instead. --- CHANGELOG.md | 2 +- .../selectedAction.validation.html | 150 ++++++++++++++++++ .../selectedAction.validation.html.snap-1.png | Bin 0 -> 6667 bytes .../selectedAction.validation.html.snap-2.png | Bin 0 -> 5530 bytes .../AdaptiveCardHacks/private/closest.ts | 18 --- .../useActionShouldBePushButtonModEffect.ts | 94 +++++------ .../Attachment/AdaptiveCardRenderer.tsx | 21 +-- 7 files changed, 206 insertions(+), 79 deletions(-) create mode 100644 __tests__/html2/accessibility/adaptiveCard/selectedAction.validation.html create mode 100644 __tests__/html2/accessibility/adaptiveCard/selectedAction.validation.html.snap-1.png create mode 100644 __tests__/html2/accessibility/adaptiveCard/selectedAction.validation.html.snap-2.png delete mode 100644 packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardHacks/private/closest.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 464d4aed73..228c7b372b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,7 +64,7 @@ Legends: - Fixed screen readers announcing a single audio, video, or animation in a card as a list item, such as "1 of 1", fixes [#5722](https://github.com/microsoft/BotFramework-WebChat/issues/5722), in PR [#5903](https://github.com/microsoft/BotFramework-WebChat/pull/5903), by [@OEvgeny](https://github.com/OEvgeny) - Fixed video and animation cards disappearing in production builds when the video URL is relative or invalid, in PR [#5889](https://github.com/microsoft/BotFramework-WebChat/pull/5889), by [@OEvgeny](https://github.com/OEvgeny) - Fixed timestamps always using the 12-hour clock, such as "4:41 PM" instead of "16:41" in German, in PR [#5920](https://github.com/microsoft/BotFramework-WebChat/pull/5920), by [@OEvgeny](https://github.com/OEvgeny) -- Fixed card action buttons, such as Adaptive Card actions and hero card buttons, being announced as toggle buttons that could not be turned off: they are now buttons, and pressed actions are described as "Selected", fixes [#5716](https://github.com/microsoft/BotFramework-WebChat/issues/5716), [#5719](https://github.com/microsoft/BotFramework-WebChat/issues/5719), [#5745](https://github.com/microsoft/BotFramework-WebChat/issues/5745), and [#5750](https://github.com/microsoft/BotFramework-WebChat/issues/5750), in PR [#5900](https://github.com/microsoft/BotFramework-WebChat/pull/5900), by [@OEvgeny](https://github.com/OEvgeny) +- Fixed card action buttons, such as Adaptive Card actions and hero card buttons, being announced as toggle buttons that could not be turned off: they are now buttons, and actions are described as "Selected" once performed, not when the card's inputs fail validation, fixes [#4583](https://github.com/microsoft/BotFramework-WebChat/issues/4583), [#5716](https://github.com/microsoft/BotFramework-WebChat/issues/5716), [#5719](https://github.com/microsoft/BotFramework-WebChat/issues/5719), [#5745](https://github.com/microsoft/BotFramework-WebChat/issues/5745), and [#5750](https://github.com/microsoft/BotFramework-WebChat/issues/5750), in PR [#5900](https://github.com/microsoft/BotFramework-WebChat/pull/5900), by [@OEvgeny](https://github.com/OEvgeny) ## [4.19.2] - 2026-10-08 diff --git a/__tests__/html2/accessibility/adaptiveCard/selectedAction.validation.html b/__tests__/html2/accessibility/adaptiveCard/selectedAction.validation.html new file mode 100644 index 0000000000..f4050c55da --- /dev/null +++ b/__tests__/html2/accessibility/adaptiveCard/selectedAction.validation.html @@ -0,0 +1,150 @@ + + + + + + +
+ + + + diff --git a/__tests__/html2/accessibility/adaptiveCard/selectedAction.validation.html.snap-1.png b/__tests__/html2/accessibility/adaptiveCard/selectedAction.validation.html.snap-1.png new file mode 100644 index 0000000000000000000000000000000000000000..4de945bb9ba095f0e40ec01311719029954f177c GIT binary patch literal 6667 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 jQVd>#CB9J@=Zbc|EH79J-PB}X5G_Q z^#F0!_|+OPk#`ysxo=xhb2^Ey6%fC8`7sW-rLOI*bBhb_@(edF12C1BRtWo}45A-) zTbbZZ&rw0HqIHBkjZoxPh1*-j1P!~?rT4)TBCVBIrf-|)VYS$$5+7yYXy}DXShJDuXU+<$1ojv1z Kn)sigSN;opS_3u! literal 0 HcmV?d00001 diff --git a/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardHacks/private/closest.ts b/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardHacks/private/closest.ts deleted file mode 100644 index fdbda5f5f5..0000000000 --- a/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardHacks/private/closest.ts +++ /dev/null @@ -1,18 +0,0 @@ -// Ponyfill `HTMLElement.closest`. -// https://developer.mozilla.org/en-US/docs/Web/API/Element/closest -export default function closest(element: HTMLElement, selector: string): HTMLElement | undefined { - if (typeof element.closest === 'function') { - return element.closest(selector); - } - - let current: HTMLElement | null = element; - - while (current) { - // "msMatchesSelector" is vendor-prefixed version of "matches". - if ((current.matches || (current['msMatchesSelector'] as (selector: string) => boolean)).call(current, selector)) { - return current; - } - - current = current.parentElement; - } -} diff --git a/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardHacks/useActionShouldBePushButtonModEffect.ts b/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardHacks/useActionShouldBePushButtonModEffect.ts index b41f064a68..be220b040b 100644 --- a/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardHacks/useActionShouldBePushButtonModEffect.ts +++ b/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardHacks/useActionShouldBePushButtonModEffect.ts @@ -1,10 +1,8 @@ -import { useMemo, useRef } from 'react'; +import { useCallback, useMemo, useRef } from 'react'; -import addEventListenerWithUndo from '../../DOMManipulationWithUndo/addEventListenerWithUndo'; import bunchUndos from '../../DOMManipulationWithUndo/bunchUndos'; import durableAddClassWithUndo from '../../DOMManipulationWithUndo/durableAddClassWithUndo'; import setOrRemoveAttributeIfFalseWithUndo from '../../DOMManipulationWithUndo/setOrRemoveAttributeIfFalseWithUndo'; -import closest from './private/closest'; import findDOMNodeOwner from './private/findDOMNodeOwner'; import useAdaptiveCardModEffect from './private/useAdaptiveCardModEffect'; import usePrevious from './private/usePrevious'; @@ -22,13 +20,21 @@ import type { UndoFunction } from '../../DOMManipulationWithUndo/types/UndoFunct * Thus, instead of `aria-pressed`, the selected action is described by the element of `descriptionId` (e.g. "Selected"), * and styled by `selectedClassName`. * + * An action is selected only after Adaptive Cards executed it, i.e. `markActionAsSelected()` is called from `onExecuteAction`. + * Adaptive Cards does not execute an action when its inputs fail validation, e.g. a required input is empty. + * * One exception is the `Action.ShowCard` action. This button represents expand/collapse header of an accordion. * Thus, their state is indicated by `aria-expanded` and they are never selected. * However, we still need to remove other unnecessary ARIA fields. */ export default function useActionShouldBePushButtonModEffect( adaptiveCard: AdaptiveCard -): readonly [(cardElement: HTMLElement, selectedClassName: string, descriptionId: string) => void, () => void] { +): readonly [ + (cardElement: HTMLElement, selectedClassName: string, descriptionId: string) => void, + () => void, + (action: CardObject) => void +] { + const markActionAsSelectedRef = useRef<((action: CardObject) => void) | undefined>(); const prevAdaptiveCard = usePrevious(adaptiveCard); const pushedCardObjectsRef = useRef>(new Set()); @@ -36,68 +42,54 @@ export default function useActionShouldBePushButtonModEffect( const modder = useMemo( () => (adaptiveCard: AdaptiveCard, cardElement: HTMLElement, selectedClassName: string, descriptionId: string) => { + const actionElements = Array.from( + cardElement.querySelectorAll('button.ac-pushButton') as NodeListOf + ); const undoStack: UndoFunction[] = []; const markAsSelected = (actionElement: HTMLElement) => + // Mods all AC action buttons except those for `Action.ShowCard`, which has `aria-expanded` attribute. + !actionElement.hasAttribute('aria-expanded') && undoStack.push( durableAddClassWithUndo(actionElement, selectedClassName), setOrRemoveAttributeIfFalseWithUndo(actionElement, 'aria-describedby', descriptionId) ); - Array.from(cardElement.querySelectorAll('button.ac-pushButton') as NodeListOf).forEach( - actionElement => { - const cardObject = findDOMNodeOwner(adaptiveCard, actionElement); - - !actionElement.hasAttribute('aria-expanded') && - pushedCardObjectsRef.current.has(cardObject) && - markAsSelected(actionElement); - - undoStack.push( - setOrRemoveAttributeIfFalseWithUndo(actionElement, 'aria-posinset', false), - setOrRemoveAttributeIfFalseWithUndo(actionElement, 'aria-setsize', false), - setOrRemoveAttributeIfFalseWithUndo(actionElement, 'role', false) - ); - } - ); - - undoStack.push( - addEventListenerWithUndo( - cardElement, - 'click', - ({ target }) => { - // Depends on click location, `target` could be the
inside the