vercel / next.js

The React Framework
https://nextjs.org
MIT License
127k stars 26.99k forks source link

`<Link>` with `href="#someexample"` will not trigger CSS target selector (`#someexample:target{...}`) #51346

Open tilman opened 1 year ago

tilman commented 1 year ago

Verify canary release

Provide environment information

Operating System:
      Platform: darwin
      Arch: arm64
      Version: Darwin Kernel Version 21.6.0: Mon Aug 22 20:19:52 PDT 2022; root:xnu-8020.140.49~2/RELEASE_ARM64_T6000
    Binaries:
      Node: 18.15.0
      npm: 9.5.0
      Yarn: 3.4.1
      pnpm: 8.6.0
    Relevant packages:
      next: 13.4.6-canary.7
      eslint-config-next: N/A
      react: 18.2.0
      react-dom: 18.2.0
      typescript: 4.9.5

Which area(s) of Next.js are affected? (leave empty if unsure)

App directory (appDir: true), Routing (next/router, next/navigation, next/link)

Link to the code that reproduces this issue or a replay of the bug

https://github.com/tilman/nextlink-css-target-selector-bug

To Reproduce

1.) Open the example under http://localhost:3000/ (for regular pages) Watch the div below the links wich should turn blue during clicking the links.

Use regular anchor tags: Click Link 1.) it to see that :target selector changed the style of a div Click Link 2.): Reset the styling with this link by changing the target to '#'

Use next Link tags: Click Link 3.) to see that :target selector does not change the style of a div if next/link is used Click Link 1.)/4.) again to set the blue bg Clink Link 5.) to reset the styling with this link by changing the target to '#'. Also does not reset the style if regular anchor tag (1./4.) was clicked before to set the style.

2.) Open the example under http://localhost:3000/appExample (for new app dir. Same behaviour)

Describe the Bug

While using a next/link the css :target selector is not working. Only if we use a regular tag.

Expected Behavior

The CSS :target selector should work with next/link the same way as with the <a> tag

Which browser are you using? (if relevant)

chrome

How are you deploying your application? (if relevant)

localhost

tilman commented 1 year ago

I guess the reason is that next/link uses window.history.pushState wich does not affect :target selector.

See here: https://bugs.chromium.org/p/chromium/issues/detail?id=89165 and here: https://github.com/whatwg/html/issues/639 and here: https://github.com/remix-run/remix/issues/6432

Seems like using window.location.hash = 'sometesttarget' will fix it. I think best would be to add this to next/router changeState function? I can open a PR for that if you want.

Phebonacci commented 11 months ago

Hi, @tilman . I found another work-around that doesn't require going forwards and backwards through the browser history. Although, I'm not sure of its implications (like if it's a code smell). I subscribed to the hashChangeStart event like so:

useEffect(() => {
  const hashChangeStartHandler = (route: string) => {
    const url = new URL(route, window.location.href);
    window.location.hash = url.hash; 
  };
  router.events.on('hashChangeStart', hashChangeStartHandler);

  return () => router.events.off('hashChangeStart', hashChangeStartHandler);
}, []);

This will trigger whatever function enables the :target selector.

ashgrover commented 3 months ago

Can confirm, this issue still exists in NextJs v14.2.5.