-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Add @bind-open support for details and dialog elements #64654
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
This change enables two-way binding on the 'open' attribute for <details> and <dialog> elements using @bind-open syntax. Changes: - Added BindElement attributes for details element in BindAttributes.cs - Changed ontoggle event handler to use ChangeEventArgs instead of EventArgs - Updated WebEventData.cs to deserialize toggle events as ChangeEventArgs - Updated EventTypes.ts to use ToggleEvent.newState for reliable state detection - Added E2E tests for details element binding Fixes #64194
There was a problem hiding this 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 enables two-way binding on the open attribute for <details> and <dialog> elements using the @bind-open syntax in Blazor. The implementation changes the ontoggle event handler to use ChangeEventArgs instead of EventArgs to support the binding infrastructure, and updates both C# and JavaScript event handling code.
Key changes:
- Added
BindElementattributes fordetailselement to enable@bind-opensyntax - Changed
ontoggleevent to useChangeEventArgswith boolean value indicating open/closed state - Updated JavaScript event parsing to use
ToggleEvent.newStatefor correct behavior across all toggle event sources
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Components/Web/src/Web/BindAttributes.cs | Added BindElement attributes for details element to enable @bind-open binding syntax |
| src/Components/Web/src/Web/EventHandlers.cs | Changed ontoggle event handler from EventArgs to ChangeEventArgs to support binding |
| src/Components/Web/src/WebEventData/WebEventData.cs | Added toggle event deserialization case to use ChangeEventArgsReader for boolean values |
| src/Components/Web.JS/src/Rendering/Events/EventTypes.ts | Implemented parseToggleEvent function using ToggleEvent.newState for all toggle event sources |
| src/Components/test/testassets/BasicTestApp/BindCasesComponent.razor | Added test markup and backing fields for details element binding scenarios |
| src/Components/test/E2ETest/Tests/BindTest.cs | Added E2E tests for details element binding with both initial states |
|
|
||
| // <details> | ||
| [EventHandler("ontoggle", typeof(EventArgs), true, true)] | ||
| // <details> and elements with popover attribute |
Copilot
AI
Dec 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment should mention <dialog> elements in addition to <details> and popover elements, since dialog elements also fire toggle events. Suggested change:
// <details>, <dialog>, and elements with popover attribute| // <details> and elements with popover attribute | |
| // <details>, <dialog>, and elements with popover attribute |
|
|
||
| // <details> element binds to the 'open' attribute using the 'ontoggle' event | ||
| [BindElement("details", null, "open", "ontoggle")] | ||
| [BindElement("details", "open", "open", "ontoggle")] |
Copilot
AI
Dec 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PR title mentions "Add @bind-open support for details and dialog elements", and the technical notes in the PR description explain that toggle events are fired by both <details> and <dialog> elements. However, only BindElement attributes for the details element are added here. To fully support the stated functionality, you should also add:
[BindElement("dialog", null, "open", "ontoggle")]
[BindElement("dialog", "open", "open", "ontoggle")]Without these attributes, @bind-open will not work for <dialog> elements despite the infrastructure being in place.
| [BindElement("details", "open", "open", "ontoggle")] | |
| [BindElement("details", "open", "open", "ontoggle")] | |
| // <dialog> element binds to the 'open' attribute using the 'ontoggle' event | |
| [BindElement("dialog", null, "open", "ontoggle")] | |
| [BindElement("dialog", "open", "open", "ontoggle")] |
| [Fact] | ||
| public void CanBindDetailsElement_InitiallyClosed() | ||
| { | ||
| var target = Browser.Exists(By.Id("details-initially-closed")); | ||
| var boundValue = Browser.Exists(By.Id("details-initially-closed-value")); | ||
| var toggleButton = Browser.Exists(By.Id("details-initially-closed-toggle")); | ||
| Assert.Null(target.GetDomAttribute("open")); | ||
| Assert.Equal("False", boundValue.Text); | ||
|
|
||
| // Click to expand; verify value is updated | ||
| target.FindElement(By.TagName("summary")).Click(); | ||
| Browser.NotEqual(null, () => target.GetDomAttribute("open")); | ||
| Browser.Equal("True", () => boundValue.Text); | ||
|
|
||
| // Click to collapse; verify value is updated | ||
| target.FindElement(By.TagName("summary")).Click(); | ||
| Browser.Equal(null, () => target.GetDomAttribute("open")); | ||
| Browser.Equal("False", () => boundValue.Text); | ||
|
|
||
| // Modify data programmatically; verify details is updated | ||
| toggleButton.Click(); | ||
| Browser.NotEqual(null, () => target.GetDomAttribute("open")); | ||
| Browser.Equal("True", () => boundValue.Text); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void CanBindDetailsElement_InitiallyOpen() | ||
| { | ||
| var target = Browser.Exists(By.Id("details-initially-open")); | ||
| var boundValue = Browser.Exists(By.Id("details-initially-open-value")); | ||
| var toggleButton = Browser.Exists(By.Id("details-initially-open-toggle")); | ||
| Assert.NotNull(target.GetDomAttribute("open")); | ||
| Assert.Equal("True", boundValue.Text); | ||
|
|
||
| // Click to collapse; verify value is updated | ||
| target.FindElement(By.TagName("summary")).Click(); | ||
| Browser.Equal(null, () => target.GetDomAttribute("open")); | ||
| Browser.Equal("False", () => boundValue.Text); | ||
|
|
||
| // Click to expand; verify value is updated | ||
| target.FindElement(By.TagName("summary")).Click(); | ||
| Browser.NotEqual(null, () => target.GetDomAttribute("open")); | ||
| Browser.Equal("True", () => boundValue.Text); | ||
|
|
||
| // Modify data programmatically; verify details is updated | ||
| toggleButton.Click(); | ||
| Browser.Equal(null, () => target.GetDomAttribute("open")); | ||
| Browser.Equal("False", () => boundValue.Text); | ||
| } |
Copilot
AI
Dec 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PR title mentions adding @bind-open support for both details and dialog elements. While tests are provided for the <details> element, there are no tests for <dialog> element binding. Consider adding E2E tests for <dialog> element binding to ensure it works correctly, since dialog elements also fire toggle events and should support @bind-open according to the PR description.
Summary
This PR adds support for two-way binding on the
openattribute for<details>and<dialog>elements using the@bind-opensyntax.Fixes #64194
Changes
C# Changes
BindElementattributes for thedetailselement to enable@bind-opensyntaxontoggleevent handler to useChangeEventArgsinstead ofEventArgsto support binding infrastructureChangeEventArgsReaderJavaScript Changes
parseToggleEventto useToggleEvent.newStateinstead of readingelement.openproperty. This correctly handles all elements that fire toggle events (<details>,<dialog>, and popover elements).Tests
Usage
Technical Notes
The toggle event is fired by:
<details>element - when expanded/collapsed<dialog>element - when shown/hiddenpopoverattribute) - when shown/hiddenUsing
ToggleEvent.newState(which is"open"or"closed") ensures correct behavior for all element types, as not all elements have anopenDOM property (popovers don't).