Hey! 👋
I ran into an interesting issue with Fluxon's accordion component in a Phoenix LiveView app and wanted to share the findings - there might be an opportunity to make Fluxon even more LiveView-friendly.
When using <.accordion> with form validation (phx-change="validate"), the accordion would collapse every time the user typed in the form input. This created a frustrating UX where users couldn't keep the form expanded while typing.
Root Cause: Fluxon's accordion stores state in private JavaScript variables (#openIndexes). When LiveView re-renders the DOM (even for form validation), the hook lifecycle destroys and recreates the accordion instance, losing the internal state.
Sequence:
- User expands accordion → Fluxon sets
#openIndexes = [0] - User types in form → LiveView validation triggers DOM patch
- Hook destroyed →
#openIndexeslost - New hook mounted → Reads template
expanded={false}→ Accordion collapses
We ended up building a simple custom accordion that uses data attributes as the state store instead of private JS variables:
// State lives in DOM, survives LiveView patches
this.el.dataset.expanded = "true";
updated() {
// Restore from data attribute after LiveView updates
const expanded = this.el.dataset.expanded === 'true';
this.setState(expanded);
}This works because:
- DOM data attributes survive LiveView patches
- No complex state synchronization needed
- Follows LiveView's recommended patterns
I wonder if Fluxon could add a "LiveView mode" that:
- Uses data attributes for state persistence instead of (or alongside) private variables
- Reads state from data attributes in
updated()hook to survive DOM patches - Maybe adds a
liveview-friendlyprop that enables this behavior
Something like:
<.accordion liveview-friendly>
<.accordion_item expanded={@form_expanded}>Where the accordion would:
- Store expanded state in
data-expandedattributes - Restore state from data attributes in the
updated()lifecycle - Still provide the same rich functionality (animations, keyboard nav, etc.)
This pattern (form validation causing component state loss) is probably common in LiveView apps. A LiveView-friendly mode could make Fluxon components more robust in this environment while maintaining all the great accessibility and animation features.
The LiveView docs actually recommend this pattern for client-side libraries:
"Changes, additions, and removals from the server to data attributes are merged with the ignored element which can be used to pass data to the JS handler."
If you're interested in exploring this, I'd be happy to:
- Share more details about the implementation
- Help test any changes
- Contribute code if needed
The current Fluxon components are awesome - this would just make them even more LiveView-friendly! 🚀