Skip to content

Filter and Sort not updating DOM on Safari iOS (Real iPhone & iPad) #792

@pepperclip-commits

Description

@pepperclip-commits

Filter and Sort not updating DOM on Safari iOS

Description

Finsweet Attributes List (@finsweet/attributes@2) initializes correctly on Safari iOS and reads all inputs properly, but the DOM never updates after the initial render when using filters or sort.

Environment

  • Package: @finsweet/attributes@2 (latest)
  • Feature: fs-list
  • Platform: Safari iOS (iPhone, iPad real device)
  • Works on: Chrome desktop, Safari desktop, Chrome mobile emulator (DevTools)
  • Fails on: Safari iOS real device only

Steps to reproduce

  1. Set up a static fs-list with filter inputs and a sort select
  2. Load the page on a real iPhone or iPad with Safari
  3. Interact with the sort <select> or filter <input type="radio">
  4. Observe that the list does not update

Debugging findings

After extensive debugging via Safari remote inspector, here is what we found:

1. Finsweet initializes correctly
The FinsweetAttributes callback fires, listInstances is available, and the initial render hook is triggered with all 12 items.

window.FinsweetAttributes.push(['list', (listInstances) => {
  console.log('List loaded'); // ✅ fires on iOS
  listInstances[0].addHook('render', (items) => {
    console.log('render', items.length); // ✅ fires once on load, never again after interaction
  });
}]);

2. Change events fire correctly
The change event on the sort <select> is detected and document.activeElement is correct:

document.querySelector('[fs-list-element="sort-trigger"]').addEventListener('change', function(e) {
  console.log('change fired', e.isTrusted); // ✅ true
  console.log('activeElement match', document.activeElement === this); // ✅ true
});

3. Internal state is updated
After interacting with the sort select, inspecting the internal state shows interacted: true and the correct fieldKey — meaning Finsweet receives and processes the event:

window._fsList.sorting._rawValue
// {fieldKey: "alpha", direction: "asc", interacted: true}

4. But the DOM never changes
Despite the state being updated, no style="display: none" or reordering is applied to fs-list-element="item" elements. The render hook never fires again after the initial load.

5. setSearchParam resolves but has no effect
Calling setSearchParam manually resolves the promise but does not trigger a DOM update:

await window._fsList.setSearchParam('sort', 'alpha-asc');
// Promise resolves ✅
// DOM does not change ❌
// sorting._rawValue still shows previous value ❌

6. URL param workaround partially works
If the sort/filter param is present in the URL on page load, the initial render applies it correctly. But subsequent interactions still have no effect.

7. Clear works once
Using fs-list-element="clear" after a URL-param-triggered filter correctly resets the list. But any interaction after that has no effect again.

Root cause hypothesis (from Claude)

Finsweet@2 uses Vue 3 reactivity internally (visible via __v_isRef, __v_isShallow, Proxy on internal objects). The state is updated correctly but the Vue reactivity system does not trigger a DOM re-render on Safari iOS. This appears to be a Vue 3 reactivity issue specific to WebKit/Safari iOS.

Available methods on list instance

Object.getOwnPropertyNames(Object.getPrototypeOf(window._fsList))
// ["constructor", "addHook", "triggerHook", "scrollToAnchor",
//  "getSearchParam", "getAllSearchParams", "setSearchParam", "listOrWrapper"]

No public render() or refresh() method is available to force a re-render as a workaround.

Expected behavior

The list should filter and sort correctly on Safari iOS real devices, just as it does on desktop browsers.

Actual behavior

The DOM never updates after the initial render when interacting with filters or sort on Safari iOS.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions