jsdom icon indicating copy to clipboard operation
jsdom copied to clipboard

Focussing an element doesn't trigger the CSS update based on the :focus pseudo class

Open tbelch-at-eHealth-Tec opened this issue 2 years ago • 8 comments

Dear jsdom team,

I'm trying to achieve the following:

Using the CSS pseudo class :focus to determine whether an element has the style display: block or none. I expect the styling of the sibling component to change, when the controlling component is focused. The same way it happens in the browser.

Basic info:

  • Node.js version: 16.13.2
  • jsdom version: 16.7.0

Minimal reproduction case

import jsdom from "jsdom";

const dom = new jsdom.JSDOM(`
  <html>
    <head>
      <style>
      #focus_input:focus + #focus_label { display: none; }
      </style>
    </head>
    <body>
      <div>
      <input
        id="focus_input"
        type="text"
      />
      <label id="focus_label">
        Focus input to hide
      </label>
    </div>
    </body>
  </html>
`);

const { document } = dom.window;

document.getElementById("focus_input").focus();

console.log(document.activeElement);
console.log(document.getElementById("focus_label").style.display); // should print "display: none"

https://codesandbox.io/s/jsdom-focus-sibling-combinator-ph3tql?file=/src/index.js

How does similar code behave in browsers?

In the browser it works as expected. See example

https://codesandbox.io/s/jsdom-focus-sibling-combinator-ph3tql?file=/index.html

tbelch-at-eHealth-Tec avatar Apr 25 '22 06:04 tbelch-at-eHealth-Tec

Just to be sure, I'm not 100% confident that in the browser it's working as it should. When calling document.getElementById("focus_input").focus(); from the console, the design doesn't really change for me, does that work for you?

MatanBobi avatar Apr 25 '22 06:04 MatanBobi

@MatanBobi Yes, for me it does work. Using https://codesandbox.io/s/jsdom-focus-sibling-combinator-ph3tql?file=/index.html I can hide the sibling item through focusing the input via console.

https://user-images.githubusercontent.com/64063903/165035748-7e8aa663-73db-4a29-bb95-01bd9ae06793.mov

tbelch-at-eHealth-Tec avatar Apr 25 '22 06:04 tbelch-at-eHealth-Tec

Try opening a new window button and use the browser console to run document.getElementById("focus_input").focus();. The label did not disappear for me on Chrome Version 101.0.4951.67 image

Vac1911 avatar May 31 '22 16:05 Vac1911

Try opening a new window button and use the browser console to run document.getElementById("focus_input").focus();. The label did not disappear for me on Chrome Version 101.0.4951.67 image

@Vac1911 That is interesting/worrying. Because it does work in the original window. And it still works when I actually click inside input_focus or focus it via TAB. But did you realise, that input_focus doesn't get a focus when calling document.getElementById("focus_input").focus();? Because it also doesn't get its focus outline.

So to me it seems that HTMLElement.focus() is simply not working correctly in the new window version of the app.

tbelch-at-eHealth-Tec avatar Jun 01 '22 06:06 tbelch-at-eHealth-Tec

But did you realise, that input_focus doesn't get a focus when calling document.getElementById("focus_input").focus();?

@tbelch-at-eHealth-Tec Yes that's what I was trying to communicate. As far as I know Element.focus() does not trigger :focus, I'm not sure why it does it in codesandbox.

Vac1911 avatar Jun 03 '22 12:06 Vac1911

I'm having a similar issue. I have an input with a gray border, when I focus I change it to black:

export const Input = styled.input`
  border-color: gray;
  
  :focus {
    border-color: black;
  }
`

When testing this input, hoping it has focus, it works

  it('should have a specif border color when focused', async () => {
    const user = userEvent.setup()

    await user.click(screen.queryByRole('textbox'))

    expect(screen.queryByRole('textbox')).toHaveFocus()
  })

But when I add the expectation that the style applies to the focus:

  it('should have a specif border color when focused', async () => {
    const user = userEvent.setup()

    await user.click(screen.queryByRole('textbox'))

    expect(screen.queryByRole('textbox')).toHaveFocus()
    expect(screen.queryByRole('textbox')).toHaveStyle(`border-color: black;`)
  })

I get that:

Screenshot from 2022-06-23 20-31-45

You can see that the .toHaveFocus succeeded but the style did not

laboriosi avatar Jun 23 '22 23:06 laboriosi

I have the same problem as the fine people above ☝️

demccormack avatar Nov 17 '22 07:11 demccormack

Look like this is related to https://github.com/dperini/nwsapi logic, but from my investigations, this moment should be fine.

  • :hover is stateful and might not work if there is no focused element at style parsing time
  • :focus-within is broken - https://github.com/dperini/nwsapi/pull/74

UPD: Just update nwsapi

theKashey avatar Jan 31 '23 06:01 theKashey