[
  {
    "path": ".nojekyll",
    "content": ""
  },
  {
    "path": ".pr-preview.json",
    "content": "{\n    \"src_file\": \"index.bs\",\n    \"type\": \"bikeshed\"\n}\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Code of Conduct\n\nAll documentation, code and communication under this repository are covered by the [W3C Code of Ethics and Professional Conduct](https://www.w3.org/Consortium/cepc/).\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Web Platform Incubator Community Group\n\nThis repository is being used for work in the W3C Web Platform Incubator Community Group, governed by the [W3C Community License\nAgreement (CLA)](http://www.w3.org/community/about/agreements/cla/). To make substantive contributions,\nyou must join the CG.\n\nIf you are not the sole contributor to a contribution (pull request), please identify all\ncontributors in the pull request comment.\n\nTo add a contributor (other than yourself, that's automatic), mark them one per line as follows:\n\n```\n+@github_username\n```\n\nIf you added a contributor by mistake, you can remove them in a comment with:\n\n```\n-@github_username\n```\n\nIf you are making a pull request on behalf of someone else but you had no part in designing the\nfeature, you can remove yourself with the above syntax.\n"
  },
  {
    "path": "EXTENSIONS.md",
    "content": "# Alternative Content Types\n\n## Introduction\n\nThe existing [scroll-to-text-fragment\nspec](https://wicg.github.io/scroll-to-text-fragment/) enables links to\nspecific textual content within a page. However there are many kinds of\nnon-textual content which may also be of interest. This document explores\nseveral use cases and proposes methods by which they may be addressed.\n\n## Use cases\n\nThere are several content types users may be trying to view when following a\nlink to see some particular content. Primarily, these are:\n\n* Text\n* Images\n* Videos\n\nIn addition to the [use cases presented for text\ncontent](README.md#motivating-use-cases), there are many use cases where the\ncontent of interest is images, video, or some element on the page.\n\n### Image aggregation or attribution\n\nImages are often collected from other sites with attribution (e.g.\n[Wikipedia articles](https://en.wikipedia.org/),\n[Pinterest](https://www.pinterest.com/),\n[Microsoft Edge collections](https://support.microsoft.com/en-us/microsoft-edge/organize-your-ideas-with-collections-in-microsoft-edge-60fd7bba-6cfd-00b9-3787-b197231b507e))\nand link back to the original content\npage. Having the ability to scroll to the image would greatly decrease the\nfriction in finding that image in its original context.\n\n### Image search engines\n\nImage search engines often provide the ability to view the image in the context\nof the original page. When the image is not at the top of the page, this results\nin an inconvenient experience, where you do not even have the ability to use the\nfind-in-page feature since there is no way to search for an image.\n\nSearch engines could use this extension to provide a link for users to scroll to\nthe relevant image in the target page.\n\n### Sharing a specific image or video\n\nJust as with text, when referencing some rich content on a web page, it is\ndesirable to be able to link directly to it. It is often the case on sites with\nmany images or videos that it could be non-trivial to find the content of\ninterest after navigating.\n\n## Principles\n\nTo enable links to non-textual content, we need to specify the content to scroll\nto. Here, we follow the same principles as with textual content:\n\n1.   Specify the content to scroll to, rather than where the content lies in the\n     structure of the page.\n1.   The simplest form of the specifier should work for most content and\n     web pages.\n1.   However, additional syntax may be necessary to work for other cases. This\n     additional syntax should only be used when necessary and may not be able to\n     specify contrived or manufactured examples, but should extend coverage\n     considerably past the most simple syntax.\n     \n## Security\n\nThe issues here are analogous to those described in\n[Restrictions for scroll-to-CSS-selectors](https://docs.google.com/document/d/15HVLD6nddA0OaI8Dd0ayBP2jlGw5JpRD-njAyY1oNZo/edit#heading=h.s4z585kmzt11)\nand\n[Text Fragment Security Issues](https://docs.google.com/document/d/1YHcl1-vE_ZnZ0kL2almeikAj2gkwCq8_5xwIae7PVik/edit#heading=h.uoiwg23pt0tx).\nIf an attacker can navigate or convince a user to navigate to a URL with a\n\"scroll-to-image\" URL, and if they can determine that the page scrolled automatically\non load (or some other side effect like longer load time), they may be able to infer\nthe existence of the resource on the page (with enough CSS selector syntax they could\nalso infer arbitrary properties of the DOM, e.g., through\n[CSS timing attacks](https://blog.sheddow.xyz/css-timing-attack/)).\n\nSimilar to the issues with text fragments, there may be cases where an attacker might\nbe able to determine the value of an attribute value. For this reason, we provide a\nlimited list of attributes which we'll allow matching; hence the\n[Restrictions](#css-selector-restrictions) section below.\n\nNote: We are still iterating on the potential consequences and mitigations here. The\nbelow proposal is a vision of where we'd like to get to but the details are still\nbeing decided.\n\n## Proposed solution\n\nWe propose a restricted CSS selector syntax in the\n[fragment directive](https://wicg.github.io/scroll-to-text-fragment/#the-fragment-directive)\nof the URL. The selector syntax is severely restricted to avoid allowing selection\nbased on arbitrary attributes or page structure.\n\n### Fragment Directive Syntax\n\nUse a slightly adapted (to fragment directives) syntax from the W3C Selectors and\nStates Reference Note for the WebAnnotations\n[CSS Selector](https://www.w3.org/TR/2017/NOTE-selectors-states-20170223/#FragmentSelector_frag).\nHere is an example:\n\n```\nhttps://example.org#:~:selector(type=CssSelector,value=img[src$=\"example.org\"])\n```\n\n![CSS Selector example showing two images in a mobile device frame with the second being selected with a CSS Selector.](https://user-images.githubusercontent.com/105274/109567247-1d79d800-7af6-11eb-8b7a-d80f7bc6fc30.png)\n\nA possible link to the image above is\n[https://github.com/WICG/scroll-to-text-fragment/blob/main/EXTENSIONS.md#:~:selector(type=CssSelector,value=img[src=%22https://user-images.githubusercontent.com/105274/109567247-1d79d800-7af6-11eb-8b7a-d80f7bc6fc30.png%22])](https://github.com/WICG/scroll-to-text-fragment/blob/main/EXTENSIONS.md#:~:selector(type=CssSelector,value=img[src=%22https://user-images.githubusercontent.com/105274/109567247-1d79d800-7af6-11eb-8b7a-d80f7bc6fc30.png%22])).\nRemember that we expect most of these links to be machine-generated.\n\nThe [Selectors and States as Fragment Identifiers](https://www.w3.org/TR/2017/NOTE-selectors-states-20170223/#h-frags)\nsection of the above Reference Note describes the functional `selector(...)` syntax\nand [CSS Selector](https://www.w3.org/TR/2017/NOTE-selectors-states-20170223/#CssSelector_def)\ndefines specifically how CSS Selectors are defined. The same note also\n[describes](https://www.w3.org/TR/2017/NOTE-selectors-states-20170223/#json-examples-converted-to-fragment-identifiers)\nhow to map the selectors into the fragment identifier syntax.\n\nThe proposal here is to levarage this work but implement only `type=CssSelector`\nand start with interpreting only the `value` key.\n\nThe fragment directive allows these selectors to co-exist with pages that use the\nfragment for routing or other reasons and is already shipped in Chrome as part of\ntext fragments.\n\nLike text fragments, multiple such directives can be supplied, mixed with\ntext fragments or other potential future directives. E.g.\n\n```\nhttps://example.org#:~:text=foo&selector(type=CssSelector…)&newThing\n```\n\nThe same handling as\n[specified in text fragments](https://github.com/WICG/scroll-to-text-fragment#multiple-text-directives)\nshould be used in this case.\n\n_Note_: Currently, the behavior is that only the first selector (from left to\nright in the URL) is scrolled into view (the rest may or may not be indicated\nby the UA). We may wish to amend this to scroll into view the first match in\n_document order_ rather than the current _selector order_.\n\n### CSS selector restrictions\n\nThe CSS selector specified in the `value=` key is restricted to a small subset of\nthe selector syntax. This prevents a potential attacker from being able to reason\nabout unrelated parts of a page or produce selectors with long runtimes.\n\nSelectors that do not meet the below restrictions will be blocked and the directive\nwill not be invoked.\n\nRestrictions:\n\n* Must be a [simple](https://www.w3.org/TR/selectors/#simple) or\n  [compound](https://www.w3.org/TR/selectors/#compound) selector\n* Uses only the following selectors:\n  * [Type](https://www.w3.org/TR/selectors/#type-selector) (i.e. element name like\n    `img`, `video`, etc.)\n  * [Class](https://www.w3.org/TR/selectors/#class-html)\n  * [Id](https://www.w3.org/TR/selectors/#id-selectors)\n  * [Attribute](https://www.w3.org/TR/selectors/#attribute-selectors)\n    * Strictly limited to: `alt`, `href`, `poster`, `src`, `srcset`, `style` attributes\n    * All [presence and value](https://www.w3.org/TR/selectors/#attribute-representation)\n      selectors allowed (i.e. `[src]`, `[src=val]`, `[src~=val]`, `[src|=val]`)\n    * All [substring matching](https://www.w3.org/TR/selectors/#attribute-substrings)\n      selectors allowed (i.e. `[src^=val]`, `[src$=val]`, `[src*=val]`)\n    * The [case sensitivity](https://www.w3.org/TR/selectors-4/#attribute-case) attribute\n      is allowed\n  * Within the constraints above, the\n    [`:has()`](https://drafts.csswg.org/selectors/#relational) pseudo-class, which is\n    useful for matching nested structures like `<video><source src=\"foo\" /></video>`\n    based on the `src` attribute.\n\n### Invocation restrictions\n\nFor the same required security reasons as text fragments, as well as to align with\nit on the basic processing model, we suggest using the same restrictions as text\nfragments (detailed in the\n[spec](https://wicg.github.io/scroll-to-text-fragment/#restricting-the-text-fragment)).\nIn summary:\n\n* Requires a user gesture/activation to have occurred\n  * Or to have occurred and been specially passed-through a\n    [client-side redirect](https://github.com/WICG/scroll-to-text-fragment/blob/master/redirects.md)\n* Requires the document to be in a top-level browsing contexts (i.e. no iframes)\n* Requires cross-document navigation, unless initiated by the user from the browser UI\n  (i.e. no same-document navigation)\n* For cross-origin navigation, requires that the browsing context be the\n  [only one in its browsing context group](https://wicg.github.io/scroll-to-text-fragment/#ref-for-document-allowtextfragmentdirective⑥:~:text=If%20document%E2%80%99s%20browsing%20context%20is%20a,to%20true%20and%20abort%20these%20sub%2Dsteps.)\n  (i.e. no other windows can script the document)\n\n### Limitations\n\nSome use cases remain difficult/impossible to select. Notably, a common pattern\nis CSS background-image specified via CSS selectors\n([example](https://www.tutorialspoint.com/how-to-create-a-hero-image-with-css)).\nIt is not clear how important/common these cases are and supporting them would either\nrequire an expanded CSS selector syntax (based on DOM structure) or a new syntax\nwhich would be less useful for other cases.\n\nOur hypothesis is that most of these cases will actually have an `id` or `class`\nattribute we could match on, or set the `background-image` using inline style.\n\n## Extensions and alternatives considered\n\n### Video timestamps\n\nWhen linking to video sources, it may be desirable to specify additional properties\nsuch as a time range to seek to or a specific track of a media element to play.\nSome video services provide this capability by parsing a parameter in the URL, but\nfor arbitrary video sites we could allow adding\n[Media Fragments](https://www.w3.org/TR/media-frags/#naming-time) to specify these\nparameters for arbitrary videos. This could work by adding the `refinedBy`\ncapability (shown here outside a URL fragment context for clarity):\n\n```\n\"selector\": {\n  \"type\": \"CssSelector\",\n  \"value\": \"video[src=example.mp4]\",\n  \"refinedBy\": {\n    \"type\": \"Fragment\",\n    \"value\": \"t=123\"\n}\n```\n\nThe interpretation being that an inner fragment selector of a media element be\napplied to its inner resource.\n\nNavigating to the above selector encoded in the `#:~:selector(...)` URL would not\nonly scroll the video into view, but also seek it to 123s.\n\n### Content-based matching\n\nThere are cases where it may not be easy to construct a selector which is both\nresilient to page layout changes while still selecting the desired content. We\ncould add an alternative type which would allow selecting based on the content\nof the result using some form of image summarization.\n\nThis has the disadvantage that it would require loading the external resources\nfirst before we could know whether it matches.\n\n## FAQs\n\n### Why use the WebAnnotations syntax?\n\nThere are a few advantages to reusing the already existing syntax offered by\nWebAnnotations:\n\n* We could decide to add more selectors in the future, either from the existing\n  WebAnnotation set or new ones — this provides a well thought out and extensible\n  framework.\n* Some of the more advanced features may prove useful, for example, the `refinedBy`\n  field. This could be used to select a video, then refine the selection using a\n  media fragment to specify the seek time. A future extension could be to also allow\n  the [spatial dimension](https://www.w3.org/TR/media-frags/#naming-space)\n  to highlight, for example, only one particular face in a group\n  picture, apart from the media fragment temporal dimension.\n* The functional syntax does have some nice advantages over the `key=value` syntax in\n  that it is easier to extend and nest.\n* It already exists, so we don't have to reinvent the wheel.\n\nThe main downsides are that it is quite verbose and departs from the `key=value` syntax\nof text fragments. We expect that CSS selectors are much less likely to be hand crafted,\nso compactness is less of an issue here than in text fragments. The fact that it differs\nfrom text fragments' syntax is unfortunate, but seems limited to aesthetic consequences.\n\n### Why such limiting restrictions on CSS Selector?\n\nMainly for security reasons. See\n[Scroll-To-Text Fragment Navigation Security Issues](https://docs.google.com/document/d/15HVLD6nddA0OaI8Dd0ayBP2jlGw5JpRD-njAyY1oNZo/edit).\n\nThough the syntax is highly restricted, between this and text fragments, this\nshould allow users to target most kinds of content they are interested in.\n\nMuch of the CSS Selector syntax has to do with structural properties of a page which\nare very powerful but may actually be harmful to the creation of resilient URLs\nsince structural properties of pages are more likely to change over time.\n\n### Why not allow combinators?\n\nWe expect [combinators](https://www.w3.org/TR/selectors/#selector-combinator)\ncould be supported without compromising security. However, we expect this may\nadd more complexity than we need and may allow creation of more brittle URLs\nthat may break when pages change.\n\nOn the other hand, allowing combinators may allow for more resilient URLs if ancestors\nof the real target have better identifying features.\n\nWe've currently left this out pending data that would indicate their necessity.\n\n### What about ambiguous cases like the same image repeated on a page?\n\nWe are not sure how common this case is.\n\nIf this does turn out to be an issue, one potential option is to implement the\n`refinedBy` field and allow restricting the selector to a subtree based on another\nelement's attribute. Another option could be to use the\n[`:nth-of-type()` pseudo class](https://drafts.csswg.org/selectors-4/#nth-of-type-pseudo).\n"
  },
  {
    "path": "LICENSE.md",
    "content": "All Reports in this Repository are licensed by Contributors\nunder the\n[W3C Software and Document License](http://www.w3.org/Consortium/Legal/2015/copyright-software-and-document).\n\nContributions to Specifications are made under the\n[W3C CLA](https://www.w3.org/community/about/agreements/cla/).\n\nContributions to Test Suites are made under the\n[W3C 3-clause BSD License](https://www.w3.org/Consortium/Legal/2008/03-bsd-license.html)\n\n"
  },
  {
    "path": "README.md",
    "content": "# Text Fragments\n\n[Draft Spec](https://wicg.github.io/scroll-to-text-fragment/)  \n[Web Platform Tests](https://wpt.fyi/results/scroll-to-text-fragment?label=experimental&label=master&aligned)  \n[ChromeStatus entry](https://chromestatus.com/feature/4733392803332096)  \n\n## Introduction\n\nTo enable users to easily link to specific content in a web page, we propose\nadding support for specifying a text snippet in the URL. When navigating to\nsuch a URL, the browser understands more precisely what the user is interested\nin on the destination page. It may then provide an improved experience, for\nexample: visually emphasizing the text or automatically bringing it into view\nor allowing the user to jump directly to it.\n\n\nWeb standards currently specify support for scrolling to anchor elements with\nname attributes, as well as DOM elements with ids, when [navigating to a\nfragment](https://html.spec.whatwg.org/multipage/browsing-the-web.html#scroll-to-fragid).\nWhile named anchors and elements with ids enable scrolling to limited specific\nparts of web pages, not all documents make use of these elements, and not all\nparts of pages are addressable by named anchors or elements with ids.\n\n### Current Status\n\nThis feature, as currently [specified in this repo](https://wicg.github.io/scroll-to-text-fragment/),\nis shipping to stable channel in Chrome M80.\n\n### Motivating Use Cases\n\nWhen following a link to read a specific part of a web page, finding the\nrelevant part of the document after navigating can be cumbersome. This is\nespecially true on mobile devices, where it can be difficult to find specific\ncontent when scrolling through long pages or using the browser's \"find in page\"\nfeature. Fewer than 1% of clients use the \"Find in Page\" feature in Chrome on\nAndroid.\n\nTo enable users to more quickly find the content they're interested in, we\npropose generalizing the existing support for scrolling to elements based on\nthe fragment identifier. We believe this capability could be used by a variety\nof websites (e.g. search engine results pages, Wikipedia reference links), as\nwell as by end users when sharing links from a browser.\n\n#### Search Engines\n\nSearch engines, which link to pages that contain content relevant to user\nqueries, would benefit from being able to scroll users directly to the part of\nthe page most relevant to their query.\n\nFor example, Google Search currently links to named anchors and elements with\nids when they are available.  For the query \"lincoln gettysburg address\nsources\", Google Search provides a link to the named anchor\n[#Lincoln’s_sources](https://en.wikipedia.org/wiki/Gettysburg_Address#Lincoln's_sources)\nfor the [wikipedia page for Gettysburg Address](https://en.wikipedia.org/wiki/Gettysburg_Address)\nas a \"Jump to\" link:\n\n![Example \"Jump to\" link in search results](jumpto.png)\n\nHowever, there are many pages with relevant passages with no named anchor or\nid, and search engines cannot provide a \"Jump to\" link in such cases.\n\n#### Citations / Reference links\n\nLinks are sometimes used as citations in web pages where the author wishes to\nsubstantiate a claim by referencing another page (e.g. references in\nWikipedia). These reference pages can often be large, so finding the exact\npassage that supports the claim can be very time consuming. By linking to the\npassage that supports their underlying claim, authors can make it more\nefficient for readers to follow their overall argument.\n\n#### Sharing a specific passage in a web page\n\nWhen referencing a specific section of a web page, for example as part of\nsharing that content via email or on social media, it is desirable to be able\nto link directly to the specific section. If a section is not linkable by a\nnamed anchor or element with id, it is not currently possible to share a link\ndirectly to a specific section.\n\nUsers may work around this by sharing screenshots of the relevant portion of\nthe document (preventing the recipient of the content from engaging with the\nactual web page that hosts the content), or by including extra instructions to\nscroll to a specific part of the document (e.g. \"skip to the sixth paragraph\").\n\nWe would like to enable users to link to the relevant section of a document\ndirectly. Linking directly to the relevant section of a document preserves\nattribution, and allows the user following the URL to engage directly with the\noriginal publisher.\n\n## Proposed Solution\n\n### tl;dr\n\nAllow specifying text as part of the URL fragment:\n\nhttps://example.com#:~:text=prefix-,startText,endText,-suffix\n\nUsing this syntax\n\n```\n:~:text=[prefix-,]textStart[,textEnd][,-suffix]\n\n         context  |-------match-----|  context\n```\n_(Square brackets indicate an optional parameter)_\n\nNavigating to such a URL will cause the browser to indicate the first instance\nof the matched text. The exact details of what a browser should do once it\nfinds a match are mostly beyond the scope of this proposal. Browsers are mostly\nfree to choose what kind of UI to surface, whether or not to scroll the text\ninto view on load, and how to visually emphasize it.\n\nTo restrict an attacker's ability to exfiltrate information across origins,\nseveral restrictions are applied on when such an anchor is activated. A user\nactivation is required and consumed; text matching can only occur on word\nboundaries. Additionally, the fragment will activate only if the document is\nsufficiently isolated from other pages (is the only one in its browsing context\ngroup, e.g.  no window.opener or iframes).\n\nThe text directive is delimited from the rest of the fragment using the `:~:`\ntoken to indicate that it is a _fragment directive_ that the user agent should\nprocess and then remove from the URL fragment that is exposed to the page. The\ndirective syntax solves the issue of compatibility with page that rely on the\nURL fragment for routing/state, see\n[issue #15](https://github.com/WICG/ScrollToTextFragment/issues/15).\n\n### Background\n\nWe propose generalizing [existing\nsupport](https://html.spec.whatwg.org/multipage/browsing-the-web.html#find-a-potential-indicated-element)\nfor scrolling to elements as part of a navigation by adding support for\nspecifying a text snippet in the URL. We modify the [indicated part of the\ndocument](https://html.spec.whatwg.org/multipage/browsing-the-web.html#the-indicated-part-of-the-document)\nprocessing model to allow using a text snippet as the indicated part. The\nuser agent may then follow the existing logic for [scrolling to the fragment identifier](https://html.spec.whatwg.org/multipage/browsing-the-web.html#scroll-to-the-fragment-identifier)\nand/or apply other UI effects.\n\nThis extends the existing support for scrolling to anchor elements with name\nattributes, as well as DOM elements with ids, to scrolling to other textual\ncontent on a web page. Browsers first attempt to find an element that matches\nthe fragment using the existing support for elements with id attributes and\nanchor elements with name attributes. If no matches are found, browsers then\nwill process the text snippet specification.\n\n### Usability Goals\n\n * Users should be able to specify multiple, non-contiguous passages. There are\n   two reasons this is important. The first is intrinsic; users sometimes want\n   to emphasise multiple snippets of a larger text. [Examples](https://twitter.com/KingJames/status/1158904415618662400)\n   [abound](https://twitter.com/surn_name/status/1205397168342716416) on\n   [Twitter](https://twitter.com/anildash/status/574389867154661377).\n\n   The second is to deal with complicated DOM cases where DOM order and text\n   order doesn't align. A common example would be a column in a table, or a\n   contiguous paragraph with an inline ad.\n\n * The user may wish to specify text that spans multiple paragraphs, list items,\n   table entries, and other structures. Our proposal aims to allow users to\n   target test crossing arbitrary DOM and visual boundaries.\n\n * The text the user wishes to target may not be unique on the page. The\n   solution must account for this by providing ways to disambiguate multiple\n   matches on a page.\n\n  * Such links should be creatable for arbitrary pages across the web. This\n    means they must be compatible with the vast majority of existing and future\n    web sites.\n\n### Identifying a Text Snippet\n\nHere's an example URL encoding some text to indicate on the destination page:\n\nhttps://en.wikipedia.org/w/index.php?title=Cat&oldid=916388819#:~:text=Claws-,Like%20almost,the%20Felidae%2C,-cats\n\n```\n:~:text=[prefix-,]textStart[,textEnd][,-suffix]\n\n         context  |-------match-----|  context\n```\n_(Square brackets indicate an optional parameter)_\n\nThough existing HTML support for id and name attributes specifies the target\nelement directly in the fragment, most other mime types make use of this x=y\npattern in the fragment, such as [Media\nFragments](https://www.w3.org/TR/media-frags/#media-fragment-syntax) (e.g.\n#track=audio&t=10,20), [PDF](https://tools.ietf.org/html/rfc3778#section-3)\n(e.g. #page=12) or [CSV](https://tools.ietf.org/html/rfc7111#section-2) (e.g.\n#row=4).\n\nThe _text_ keyword will be used to identify a block of text that should be\nindicated.  The provided text is percent-decoded before matching. Dash (-),\nampersand (&), and comma (,) characters in text snippets must be\npercent-encoded to avoid being interpreted as part of the text fragment\nsyntax.\n\nThe [URL standard](https://url.spec.whatwg.org/) specifies that a fragment can\ncontain [URL code points](https://url.spec.whatwg.org/#url-code-points), as\nwell as [UTF-8 percent encoded\ncharacters](https://url.spec.whatwg.org/#utf-8-percent-encode). Characters in\nthe [fragment percent encode\nset](https://url.spec.whatwg.org/#fragment-percent-encode-set) must be percent\nencoded.\n\nThere are two kinds of terms specified in the text directive: the _match_ and\nthe _context_. The match is the portion of text that’s to be indicated. The\ncontext is used only to disambiguate the match and is not highlighted.\n\nContext is optional, it need not be provided. However, the text directive must\nalways specify a match term.\n\n#### Match\nA match can be specified as either a single argument or as a pair.\n\nIf the match is provided using two arguments, the left argument is considered\nthe starting snippet and the right argument is considered the ending snippet\n(e.g. `text=_startText_,_endText_`). In this case, the browser will perform\na \"range search\" for a block of text that starts with _startText_ and ends with\n_endText_. If multiple blocks match the first in DOM order is chosen (i.e. find\nthe first occurrence of startText, from there find the first occurrence of\nendText). When a match is specified with two arguments, we allow highlighting\ntext that spans multiple elements.\n\nIf the match is specified as a single argument, we consider it an \"exact\nsearch\" (e.g. `text=_textSnippet_`). The browser will highlight the first\noccurrence of exactly the _textSnippet_ string. In this case, the specified text\nwill be matched only if it is contained within a single node.\n\nRange matches are useful when the desired text match is extremely long.\nFor example, selecting multiple paragraphs of text using an exact match would\nresult in a very long and cumbersome URL.\n\n<table><tr><td>\nE.g. Given:\n            \n * Text1\n * Text2\n * Text3\n * Text4\n\n`text=Text2,Text4` will highlight all items except the first:\n\n* Text1\n* __Text2__\n* __Text3__\n* __Text4__\n\n`text=Text2` will highlight just the second item:\n\n* Text1\n* __Text2__\n* Text3\n* Text4\n\n</td></tr></table>\n\n#### Context\n\nTo disambiguate non-unique snippets of text on a page, arguments can\nspecify optional _prefix_ and _suffix_ terms. If provided, the match term will\nonly match text that is immediately preceded by the _prefix_ text and/or\nimmediately followed by the _suffix_ text (allowing for an arbitrary amount of\nwhitespace in between). Immediately preceded, in these cases, means there are\nno other text nodes between the match and the context term in DOM order. There\nmay be arbitrary whitespace and the context text may be the child of a\ndifferent element (i.e. searching for context crosses element boundaries).\n\nIf provided, the prefix must end (and suffix must begin) with a dash (-)\ncharacter. This is to disambiguate the prefix and suffix in the presence of\noptional parameters. It also leaves open the possibility of extending the\nsyntax in the future to allow multiple context terms, allowing more complicated\ncontext matching across elements.\n\nIf provided, the prefix must be the first argument to the text directive.\nSimilarly, the suffix must be the last argument.\n\n<table><tr><td>\n\nFor example, suppose we want to perform the following highlight:\n\n![The highlighted text appears multiple times](draft96.png)\n\nSince the text “United States” is ambiguous, we must provide a suffix to disambiguate it:\n\n`text=United States,-Minnesota Timberwolves`\n\n</td></tr></table>\n\n### Multiple Text Directives\n\nUsers can specify multiple snippets by providing additional text directives in\nthe _fragment directive_, separated by the ampersand (&) character.\n\nEach `text=` directive is considered independent in the sense that success or\nfailure to match in one does not affect matching of any others. Each starts\nsearching from the top of the document.\n\nOnly the left-most, successfully matched, directive will be the indicated part\nof the document (i.e. used as the CSS target, scrolled into view). That is, if\n“foo” did not appear anywhere on the page but “bar” does, we scroll “bar” into\nview. However, all matched directives will be visually indicated on the page.\n\n<table><tr><td>\nFor example:\n\n```\nexample.com#:~:text=foo&text=bar&text=baz\n```\n\nwill target each of “foo”, “bar”, and “baz” and use the “foo” result as the\nindicated part of the document, assuming all appear on the page.\n\n</td></tr></table>\n\nMultiple terms can be useful when the desired text has unrelated inline\nelements like images, ads, tables, etc:\n\n![Highlighted text has an unrelated table inline](baracuda.png)\n\nUsers may also wish to emphasize multiple passages of a larger text. We've\nfound many such examples online:\n\n![Example of an screenshot with multiple highlights](twitter.png)\n\n### Fragment Directive\n\nSome existing pages on the web use fragments for their own state/routing. These\npages may break if an unexpected fragment is provided. See\n[#15](https://github.com/WICG/ScrollToTextFragment/issues/15)\n\nElement-id based fragments also cause these pages to break; however, text\nfragments are much more likely to be user-generated and are thus more likely to\ncause unexpected breakage. Pages that rely on fragment routing are also\nunlikely to provide anchor points, whereas they are likely to have text.\n\nOur solution to this is to introduce the concept of a _fragment directive_.\nThe fragment directive is a specially-delimited part of the URL fragment that\nis meant for UA instructions only. It's stripped out from the URL during\ndocument loading so that it's completely invisible to the page.\n\nThis allows specifying UA instructions like a text fragment in a way that's\nguaranteed not to interfere with page script and ensures maximal compatibility\nwith the existing web.\n\nHowever, stripping arbitrary parts of a fragment may not be web compatible! We\nwent through several ideas here:\n\n#### The Double-Hash\n\nWe tried delimiting the fragment directive using `##`. It's ergonomic and works\nwell since, if the original URL doesn't have a fragment, the double-hash\ndelimiter will already be parsed as a fragment!\n\nHowever, `#` is [not a valid code\npoint](https://url.spec.whatwg.org/#url-code-points) in the URL spec. As was\nexplained in a thread on the [w3.org URI mailing\nlist](https://lists.w3.org/Archives/Public/uri/2019Sep/0000.html), some URL\nparsers parse from right to left. Having an additional `#` character will cause\nthese parsers to break. Worse, we don't have a good way to measure the risk.\n\nUse counters we added to Chrome in M77 showed that, on Windows, about 0.08% of\npage loads already have a `#` character in the fragment. While small, that's a\nnon trivial percentage.\n\n#### Enter :~:\n\nA new delimiter would have to be both spec-compliant with the URL spec and have\nsufficiently low usage on the existing web such that this change would be\nweb-compatible.\n\nWe assumed this would preclude any single or double character sequences and\nproduced a list of candidates to consider:\n* !~!\n* !~~!\n* \\~&\\~\n* :~:\n* \\~@\\~\n* \\~\\_\\~\n* \\_~\\_\n\nWe also considered using a more verbose delimiter:\n* &directive\n* @directive\n* $directive\n* /directive\n* -directive\n\nLooking through links seen in the last 5 years by the Google Search crawler, we\neliminated some of this list. None of the \"verbose\" list had been seen;\nhowever, given valid candidates in the first list, we prefered them for\nsuccinctness and to reduce English-centric keywords.\n\nOf the above list, the following had never been seen in a URL fragment by the\ncrawler:\n\n* \\~&\\~ no hits\n* :~: no hits\n* \\~@\\~ one hit\n\nWhile this doesn't guarantee compatibility, it did give us some confidence.  We\nchose `:~:` from this list somewhat arbitrarily. However, we've also added\nChrome use-counters to M78 for all these delimiters. `:~:` is seen on fewer\nthan 0.0000039% of page loads (or about 1 in 25 million) so we currently\nbelieve this is a safe choice.\n\n#### Directives and Delimiters\n\nWhen appending the `:~:` token to a URL, it must appear inside a fragment so a\n`#` must also be added:\n\n`https://example.com` --> `https://example.com#:~:text=foo`\n\nHowever, a URL with an existing fragment can simply be appended to:\n\n`https://example.com#fallback:~:text=foo`\n\nIn this case, if the text match isn't found, the browser can fallback to\nscrolling the element-id specified in the fragment (e.g. id=\"fallback\" in this\ncase). Note that the text directive will always begin searching at the top of\nthe document, even if a matching element-id fragment is provided.\n\n#### Compatibility and Interop\n\nUser agents that haven't implemented this feature won't know how to process the\nfragment directive. Because it is part of the fragment, on most pages this will\nsimply be processed as a non-existent fragment so the page will load scrolled\nto the top, as if a fragment weren't supplied. This is a graceful fallback.\n\nA more risky scenario is apps that use the fragment for state and routing. In\nthese cases, the page is using the fragment in an application-defined manner and\nadding any content to it impact how the page operates (this is one of the\nmotivating cases for using the fragment delimiter for `text=`).\n\nIn the worst case, such a URL on an unimplementing UA may navigate to a broken\npage. However, most such pages we've seen handle this gracefully, e.g.:\n\nhttps://groups.google.com/a/chromium.org/forum/#!topic/blink-dev/OOZIrtSPLeM:~:text=test\n\nIs a Google Groups post with a directive appended. Loading it in an\nunimplementing UA displays an \"The input is invalid.\" toast in the corner but the\npage otherwise loads as if without the directive. We expect many cases will\nbehave similarly but the potential of more serious breakage does exist.\n\nNote: the fragment directive behavior (stripping everything after and including\nthe `:~:` delimiter from the fragment) can be implemented independently of the\nlarger proposal.\n\n### Feature Detection and Future APIs\n\nAn author may wish to detect whether a UA has implemented support for\ntext-fragments. This can be used by pages that generate such links to avoid\ngenerating fragment-directives for non-implementing UAs. It can also be used by\nlibraries or authors to strip the fragment-directive from user or author\ngenerated links.\n\nThis proposal includes a new property on the `document` object:\n\n```\ndocument.fragmentDirective\n```\n\nAuthors can check for the existence of this (currently empty) object to\ndetermine if a UA has implemented support for text-fragments.\n\nThis also serves as an extension point for future APIs. For example, we'd like\nto expose information about the text-fragments included in the URL so that\nauthors can build functionality on it. See\n[#128](https://github.com/WICG/scroll-to-text-fragment/issues/128) for more\ndetails.\n\n### :target\n\nFor element-id based fragments (e.g.\nhttps://en.wikipedia.org/wiki/Cat#References), navigation causes the identified\nelement to receive the `:target` CSS pseudo-class. This is a nice feature as it\nallows the page to add some customized highlighting or styling for an element\nthat’s been targeted. For example, note that navigating to a citation on a\nWikipedia page highlights the citation text:\nhttps://en.wikipedia.org/w/index.php?title=Cat&direction=prev&oldid=916388819#cite_note-Linaeus1758-1\nThe `:target` CSS pseudo-class can only apply to elements whereas a text\nsnippet may only be a portion of the text in a node or span multiple nodes.\n\nThe `:target` pseudo-class is applied to the first common ancestor element that\ncontains all the matching text, for the left-most matching `text=` directive.\n\n### Security Considerations\n\n_Some of the more detailed reasoning behind the security decisions is described\nin our [security review doc](https://docs.google.com/document/d/1YHcl1-vE_ZnZ0kL2almeikAj2gkwCq8_5xwIae7PVik/edit#heading=h.g7hd03ifqsc)_\n\nIf an attacker can detect a side-effect of a successful match, this feature\ncould be used to detect the presence of arbitrary text on the page. For\nexample, if the UA scrolls to the targeted text on navigation, an attacker\nmight be able to determine whether a scroll occurred by listening to network\nrequests or using an IntersectionObserver from an attacker-controlled iframe\nembedded on the target page.\n\nA related attack is possible if the existence of a match takes significantly\nmore or less work than non-existence. An attacker can navigate to a text\n_fragment directive_ and time how busy the JS thread is; a high load may imply\nthe existence or non-existence of an arbitrary text snippet. This is a\nvariation of a documented\n[proof-of-concept](https://blog.sheddow.xyz/css-timing-attack/).\n\nUAs are free to determine how a successfully matched text fragment should be\nsurfaced to the user based on their own assessment of how much risk certain\nactions present. For example, whether scrolling on navigation is likely to be\ndetectable in enough cases.\n\nTo prevent brute force attacks from guessing important words on a page (e.g.\npasswords, pin codes), matches and prefix/suffix are only matched on word\nboundaries. E.g.  “range” will match in “mountain range” but not in “color\norange” nor “forest ranger”.\n\nWord boundaries are simple in languages with spaces but can become more subtle\nin languages without breaks (e.g. Chinese). A library like ICU [provides\nsupport](http://userguide.icu-project.org/boundaryanalysis#TOC-Word-Boundary)\nfor finding word boundaries across all supported languages based on the Unicode\nText Segmentation standard. Some browsers already allow word-boundary\nmatching for the window.find API which allows specifying wholeWord as an\nargument. We hope this existing usage can be leveraged in the same way.\n\nAdditionally, a text directive is invoked only if a user activation occurred and\nthe loaded document is the only one in its browsing context group. The latter\nrestriction is effectively requiring `rel=noopener` be specified on a\nnavigation.\n\nVisual emphasis is performed using a visual-only indicator (i.e. don’t cause\nselection), styled by the UA and undetectable from script. This helps prevents\ndrag-and-drop or copy-paste attacks.\n\n#### Client-Side Redirects\n\nDue to the prevelance of client-side redirects (i.e. loading a document that\nnavigates via e.g. `window.location`), special care is taken to enable these\nscenarios, despite the fact they lack a user activation. See\n[redirects.md](redirects.md) for details.\n\n### Opting Out\n\nFor product reasons, or acute privacy restrictions, pages may wish to disallow\nscrolling to a text fragment (or regular fragment) on load, see\n[#80](https://github.com/WICG/ScrollToTextFragment/issues/80). To allow websites\nto opt out of text fragments, we propose adding a [Document\nPolicy](https://github.com/w3c/webappsec-feature-policy/blob/master/document-policy-explainer.md)\nnamed force-load-at-top that ensures the page is loaded without any form of\nscrolling, including via text fragments, regular element fragments, and scroll\nrestoration. Websites can use this document policy by serving the HTTP header:\n\n```\nDocument-Policy: force-load-at-top\n```\n\n## Alternatives Considered\n\n### Text Fragment Directive 0.1\n\nA prior revision of this document contained a somewhat similar proposal. The\nmain difference in the updated proposal is that it adds context terms to the\ntext directive. This helps to allow disambiguating text on a page as well as\nbrings this proposal more in-line with the Open Annotation's\n[TextQuoteSelector](https://www.w3.org/TR/annotation-model/#text-quote-selector).\nMany use cases and details were considered while iterating on the initial\nrevision. The updated proposal is a sum of lessons learned and improved\nunderstanding as we experimented with and considered the initial version and\nits limitations\n\n### CSS Selector Fragments\n\nOur initial idea, explored in some detail, was to allow encoding a CSS selector\nin the URL fragment. The selector would determine which element on the page\nshould be the \"indicated element\" in the [navigating to a\nfragment](https://html.spec.whatwg.org/multipage/browsing-the-web.html#scroll-to-fragid)\nsteps. In fact, this explainer is based on @bryanmcquade's original [CSS\nSelector Fragment\nexplainer](https://github.com/bryanmcquade/scroll-to-css-selector).\n\nThe main drawback with this approach was making it secure. Allowing scroll on\nload to a CSS selector allows several ways an attacker could exfiltrate hidden\ninformation (e.g. CSRF tokens) from the page. One such attack is demonstrated\n[here](https://blog.sheddow.xyz/css-timing-attack/) but others were quickly\ndiscovered as well.\n\nTrying to pare down the allowable set of primitives to make selectors secure\nturned out to be quite complex. Text snippets, which can be searched\nasynchronously and are generally less security sensitive, became our preferred\nsolution. As an additional bonus, we expect text snippets to be more stable and\neasier to understand by non-technical users.\n\n### Increase use of elements with named anchors / id attributes in existing web pages\n\nAs an alternative, we could ask web developers to include additional named\nanchor tags in their pages, and reference those new anchors. There are two\nissues that make this less appealing. First, legacy content on the web won’t\nget updated, but users consuming that legacy content could still benefit from\nthis feature. Second, it is difficult for web developers to reason about all of\nthe possible points other sites might want to scroll to in their pages. Thus,\nto be most useful, we prefer a solution that supports scrolling to any point in\na web page.\n\n### JavaScript-based API (instead of URL fragment)\n\nWe also considered specifying the target element via a JavaScript-based\nnavigation API, such as via a new parameter to location.assign(). It was\nconcluded that such an API is less useful, as it can only be used in contexts\nwhere JavaScript is available. Sharing a link to a specific part of a document\nis one use case that would not be possible if the target element was specified\nvia a JavaScript API. Using a JavaScript API is also less consistent than\nexisting cases where a scroll target is specified in a URL, such as the\nexisting support in HTML, as well as support for other document formats such as\nPDF and CSV.\n\n## Future Work\n\nOne important use case that's not covered by this proposal is being able to\nscroll to an image. A nearby text snippet can be used to scroll to the image\nbut it depends on the page and is indirect. We'd eventually like to support\nthis use case more directly.\n\nA potential option is to consider this just one of many available [Open\nAnnotation selectors](https://www.w3.org/TR/annotation-model/#selectors).\nFuture specification and implementation work could allow using selectors other\nthan TextQuote to allow targetting various kinds of content.\n\nAnother avenue of exploration is allowing users to specify highlighting in more\ndetail. There are also cases where the user may wish to prevent highlights\naltogether, as in the image search case described above.\n\nWe've thought about these cases insofar as making sure our proposed solution\ndoesn't preclude these enhancements in the future. However, the work of\nactually realizing them will be left for future iterations of this effort.\n\n## Additional Considerations\n\n### Constructing Arguments to Text Fragments\n\nWe imagine URLs with text fragment directives to primarily be\nmachine-generated rather than crafted by hand by users. At the same time, we\nbelieve there's a benefit to keeping the URL relatively\nhuman-readable: in most cases, simply copying and pasting the desired passage\nshould generate a text fragment directive that will scroll and highlight the\ndesired passage.\n\nThe two systems that we believe will generate the bulk of such URLs are\nbrowsers and search engines. We forsee users selecting text from the browser,\nwith an option to \"share a link to here\". These links can then be shared\nfurther as wikipedia reference links or over channels like social media or\nemail.\n\nSearch engines can also generate text directive URLs as links to search results\nfor user queries; these links may scroll to and highlight relevant passages to\nthe user's query. Note that even though using the selected text as the\ntextStart argument to the text directive may work reasonably well in practice\nas a heuristic, generating URLs targetting arbitrary text requires access to\nthe full document text up to the desired text. Both browsers and search\nengines have access to the entire visible text of the page, so it is indeed\npossible for these systems to generate proper URLs with text directive\narguments that scroll and highlight any arbitrary text.\n\n### Web and Browser Compatibility\n\nAs noted in [issue #15](https://github.com/WICG/ScrollToTextFragment/issues/15),\nweb pages could potentially be using the fragment to store parameters, e.g.\n`http://example.com/#name=test`. If sites don't handle unexpected tokens when\nprocessing the fragment, this feature could break those sites. In particular,\nsome frameworks use the fragment for routing. This is solved by the user agent\nhiding the :~:text part of the fragment from the site, but browsers that\ndo not have this feature implemented would still break such sites.\n\nFor pages that don't process the fragment, a browser that doesn't yet support\nthis feature will attempt to process the fragment and _fragment directive_\n(i.e. :~:text) using the existing logic to find a [potential indicated\nelement](https://html.spec.whatwg.org/multipage/browsing-the-web.html#find-a-potential-indicated-element).\nIf a fragment exists in the URL alongside the _fragment directive_, the browser\nmay not scroll to the desired fragment due to the confusion with parsing the\n_fragment directive_.  If a fragment does not exist alongside the _fragment\ndirective_, the browser will just load the page and won't initiate any\nscrolling.  In either case, the browser will just fall back to the default\nbehavior of not scrolling the document.\n\n### Relation to existing support for navigating to a fragment\n\nBrowsers currently support scrolling to elements with ids, as well as anchor\nelements with name attributes. This proposal is intended to extend this\nexisting support, to allow navigating to additional parts of a document. As\nShaun Inman [notes](https://shauninman.com/archive/2011/07/25/cssfrag) (in\nsupport of CSS selector fragments), this feature is \"not meant to replace more\nconcise, author-designed urls\" using id attributes, but rather \"enables a\nsite’s users to address specific sub-content that the site’s author may not\nhave anticipated as being interesting\".\n\n## Related Work / Additional Resources\n\n### Using CSS Selectors as Fragment Identifiers\n\nSimon St. Laurent and Eric Meyer\n[proposed](http://simonstl.com/articles/cssFragID.html) using CSS Selectors as\nfragment identifiers (last updated in 2012). Their proposal differs only in\nsyntax used: St. Laurent and Meyer proposed specifying the CSS selector using a\n```#css(...)``` syntax, for example ```#css(.myclass)```. This syntax is based\non the XML Pointer Language (XPointer) Framework, an \"extensible system for XML\naddressing\" ... \"intended to be used as a basis for fragment identifiers\".\nXPointer does not appear to be supported by commonly used browsers, so we have\nelected to not depend on it in this proposal.\n\n[Shaun Inman](https://shauninman.com/archive/2011/07/25/cssfrag) and others\nlater implemented browser extensions using this #css() syntax for Firefox,\nSafari, Chrome, and Opera, which shows that it is possible to implement this\nfeature across a variety of browsers.\n\nThe [Open Annotation Community\nGroup](https://www.w3.org/community/openannotation/) aims to allow annotating\narbitrary content. There is significant overlap in our goal of specifying a\nsnippet of text in a resource. In fact, they've already specified a\n[TextQuoteSelector](https://www.w3.org/TR/annotation-model/#text-quote-selector)\nfor similar purposes.\n\nThis proposal has been made similar to the TextQuoteSelector in hopes that we\ncan extend and reuse that processing model rather than inventing a new one,\nalbeit with a stripped down syntax for ease of use in a URL. Our work has been\ninformed specifically by prior efforts at selecting arbitrary textual content\nfor an annotation.\n\nScroll Anchoring\n\n* [https://drafts.csswg.org/css-scroll-anchoring/](https://github.com/WICG/ScrollAnchoring/blob/master/explainer.md)\n* [https://docs.google.com/document/d/1YaxJ0cxFADA_xqUhGgHkVFgwzf6KXHaxB9hPksim7nc/edit](https://docs.google.com/document/d/1YaxJ0cxFADA_xqUhGgHkVFgwzf6KXHaxB9hPksim7nc/edit)\n\nScroll to text\n\n* [https://indieweb.org/fragmention](https://indieweb.org/fragmention)\n* [http://zesty.ca/crit/draft-yee-url-textsearch-00.txt](http://zesty.ca/crit/draft-yee-url-textsearch-00.txt)\n* [http://1997.webhistory.org/www.lists/www-talk.1995q1/0284.html](http://1997.webhistory.org/www.lists/www-talk.1995q1/0284.html)\n* [Fragment Search - A Greasemonkey script by Gervase Markham](http://www.gerv.net/software/fragment-search/)\n* [NYT Emphasis](https://open.blogs.nytimes.com/2011/01/11/emphasis-update-and-source/)\n\nOther\n\n* [https://en.wikipedia.org/wiki/Fragment_identifier#Examples](https://en.wikipedia.org/wiki/Fragment_identifier#Examples)\n* [https://www.w3.org/TR/2017/REC-annotation-model-20170223/](https://www.w3.org/TR/2017/REC-annotation-model-20170223/)\n\n## Acknowledgements\n\nMany people have contributed greatly to the ideas and content in this repo, both through excellent work on linking\nto text as well as direct feedback and comments in issues on this repo which helped to improve this feature. In particular,\nwe'd like to thank:\n\n * @BigBlueHat\n * Ivan Herman\n * Randall Leeds\n * Kevin Marks\n * Isiah Meadows\n * Wes Turner\n * Dan Whaley\n * Gerben\n * And many others who've provided comments, questions, examples, and opinions. Thank you!\n"
  },
  {
    "path": "css-selector-example.excalidraw",
    "content": "{\n  \"type\": \"excalidraw\",\n  \"version\": 2,\n  \"source\": \"https://excalidraw.com\",\n  \"elements\": [\n    {\n      \"type\": \"rectangle\",\n      \"version\": 742,\n      \"versionNonce\": 122107777,\n      \"isDeleted\": false,\n      \"id\": \"lcrEjzTcvsnqCXMRhR73K\",\n      \"fillStyle\": \"hachure\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 106.06692764139655,\n      \"y\": 332.377492514256,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"#fa5252\",\n      \"width\": 236.7746337205807,\n      \"height\": 129.787724922286,\n      \"seed\": 646790319,\n      \"groupIds\": [\n        \"gD2XCRAxOPwO016gN3k8K\",\n        \"anexpbYoO2jKWqOt-zdc8\",\n        \"rJ1P0XBbGfURJW4Zjp7X8\"\n      ],\n      \"strokeSharpness\": \"sharp\",\n      \"boundElementIds\": []\n    },\n    {\n      \"type\": \"line\",\n      \"version\": 917,\n      \"versionNonce\": 1569373455,\n      \"isDeleted\": false,\n      \"id\": \"FK15perkdTIbBXlYgK_3F\",\n      \"fillStyle\": \"hachure\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 152.69983537715996,\n      \"y\": 430.2318294426176,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"#fa5252\",\n      \"width\": 148.11144963359644,\n      \"height\": 68.09092907653181,\n      \"seed\": 1098213825,\n      \"groupIds\": [\n        \"gD2XCRAxOPwO016gN3k8K\",\n        \"anexpbYoO2jKWqOt-zdc8\",\n        \"rJ1P0XBbGfURJW4Zjp7X8\"\n      ],\n      \"strokeSharpness\": \"round\",\n      \"boundElementIds\": [],\n      \"startBinding\": null,\n      \"endBinding\": null,\n      \"points\": [\n        [\n          0,\n          2.790571850159554\n        ],\n        [\n          41.95525895647642,\n          -37.66300434880757\n        ],\n        [\n          77.85985467458359,\n          2.2434161645777104\n        ],\n        [\n          64.57235857289969,\n          -27.997918515902047\n        ],\n        [\n          101.18386346143059,\n          -65.0926776960784\n        ],\n        [\n          148.11144963359644,\n          2.9982513804534108\n        ]\n      ],\n      \"lastCommittedPoint\": null,\n      \"startArrowhead\": null,\n      \"endArrowhead\": null\n    },\n    {\n      \"type\": \"rectangle\",\n      \"version\": 674,\n      \"versionNonce\": 592879457,\n      \"isDeleted\": false,\n      \"id\": \"e0uonrrJB7RnCbnw18CFj\",\n      \"fillStyle\": \"hachure\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 107.60171486875981,\n      \"y\": 475.9818318740939,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"#868e96\",\n      \"width\": 130.4555714909401,\n      \"height\": 19.021351602145263,\n      \"seed\": 1245695695,\n      \"groupIds\": [\n        \"anexpbYoO2jKWqOt-zdc8\",\n        \"rJ1P0XBbGfURJW4Zjp7X8\"\n      ],\n      \"strokeSharpness\": \"sharp\",\n      \"boundElementIds\": []\n    },\n    {\n      \"type\": \"rectangle\",\n      \"version\": 807,\n      \"versionNonce\": 1517175599,\n      \"isDeleted\": false,\n      \"id\": \"ux_vPeP2FjQxGtedzJcyi\",\n      \"fillStyle\": \"hachure\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 107.44325076734378,\n      \"y\": 507.33059857609067,\n      \"strokeColor\": \"#495057\",\n      \"backgroundColor\": \"#c8c8c8\",\n      \"width\": 234.58031502098106,\n      \"height\": 8.291671828836343,\n      \"seed\": 1434749345,\n      \"groupIds\": [\n        \"anexpbYoO2jKWqOt-zdc8\",\n        \"rJ1P0XBbGfURJW4Zjp7X8\"\n      ],\n      \"strokeSharpness\": \"sharp\",\n      \"boundElementIds\": []\n    },\n    {\n      \"type\": \"rectangle\",\n      \"version\": 889,\n      \"versionNonce\": 2095975233,\n      \"isDeleted\": false,\n      \"id\": \"S-8tkvQZ1ccZ8DhtGl53_\",\n      \"fillStyle\": \"hachure\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 108.24355564539394,\n      \"y\": 538.783039969076,\n      \"strokeColor\": \"#495057\",\n      \"backgroundColor\": \"#c8c8c8\",\n      \"width\": 171.18588382992098,\n      \"height\": 10.68065988086736,\n      \"seed\": 437984495,\n      \"groupIds\": [\n        \"anexpbYoO2jKWqOt-zdc8\",\n        \"rJ1P0XBbGfURJW4Zjp7X8\"\n      ],\n      \"strokeSharpness\": \"sharp\",\n      \"boundElementIds\": []\n    },\n    {\n      \"type\": \"rectangle\",\n      \"version\": 424,\n      \"versionNonce\": 423363919,\n      \"isDeleted\": false,\n      \"id\": \"LTeTLw4-V-erkZqztnzKw\",\n      \"fillStyle\": \"hachure\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 90.47168521681681,\n      \"y\": 308.602044823764,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"transparent\",\n      \"width\": 268.0068597560985,\n      \"height\": 324.33784298780483,\n      \"seed\": 2120527233,\n      \"groupIds\": [\n        \"anexpbYoO2jKWqOt-zdc8\",\n        \"rJ1P0XBbGfURJW4Zjp7X8\"\n      ],\n      \"strokeSharpness\": \"sharp\",\n      \"boundElementIds\": []\n    },\n    {\n      \"type\": \"rectangle\",\n      \"version\": 868,\n      \"versionNonce\": 745339681,\n      \"isDeleted\": false,\n      \"id\": \"0zHaZqIjHeXjoa9EYf1lo\",\n      \"fillStyle\": \"hachure\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 107.44325076734378,\n      \"y\": 523.4176793687733,\n      \"strokeColor\": \"#495057\",\n      \"backgroundColor\": \"#c8c8c8\",\n      \"width\": 234.58031502098106,\n      \"height\": 8.291671828836343,\n      \"seed\": 161982223,\n      \"groupIds\": [\n        \"anexpbYoO2jKWqOt-zdc8\",\n        \"rJ1P0XBbGfURJW4Zjp7X8\"\n      ],\n      \"strokeSharpness\": \"sharp\",\n      \"boundElementIds\": []\n    },\n    {\n      \"type\": \"rectangle\",\n      \"version\": 1063,\n      \"versionNonce\": 1498186607,\n      \"isDeleted\": false,\n      \"id\": \"iDZVpBQXobcK1N-sV09xm\",\n      \"fillStyle\": \"hachure\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 108.27622837285901,\n      \"y\": 577.0030823608798,\n      \"strokeColor\": \"#495057\",\n      \"backgroundColor\": \"transparent\",\n      \"width\": 140.1147017031425,\n      \"height\": 34.93028752594739,\n      \"seed\": 55924065,\n      \"groupIds\": [\n        \"anexpbYoO2jKWqOt-zdc8\",\n        \"rJ1P0XBbGfURJW4Zjp7X8\"\n      ],\n      \"strokeSharpness\": \"round\",\n      \"boundElementIds\": []\n    },\n    {\n      \"type\": \"text\",\n      \"version\": 1186,\n      \"versionNonce\": 306376449,\n      \"isDeleted\": false,\n      \"id\": \"NpSm2fhGe-sjutjPq7A44\",\n      \"fillStyle\": \"hachure\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 137.31980388547265,\n      \"y\": 587.5255710657228,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"transparent\",\n      \"width\": 64,\n      \"height\": 16,\n      \"seed\": 123596079,\n      \"groupIds\": [\n        \"anexpbYoO2jKWqOt-zdc8\",\n        \"rJ1P0XBbGfURJW4Zjp7X8\"\n      ],\n      \"strokeSharpness\": \"sharp\",\n      \"boundElementIds\": [],\n      \"fontSize\": 12.520371366409199,\n      \"fontFamily\": 1,\n      \"text\": \"Read more\",\n      \"baseline\": 11,\n      \"textAlign\": \"left\",\n      \"verticalAlign\": \"top\"\n    },\n    {\n      \"type\": \"line\",\n      \"version\": 1071,\n      \"versionNonce\": 1525169551,\n      \"isDeleted\": false,\n      \"id\": \"jhfzTBh9ZxEk0Diw9MH03\",\n      \"fillStyle\": \"hachure\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 4.71238898038469,\n      \"x\": 219.34119291300533,\n      \"y\": 591.5481156506379,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"#c8c8c8\",\n      \"width\": 14.737361275147578,\n      \"height\": 7.854738974308068,\n      \"seed\": 396755265,\n      \"groupIds\": [\n        \"anexpbYoO2jKWqOt-zdc8\",\n        \"rJ1P0XBbGfURJW4Zjp7X8\"\n      ],\n      \"strokeSharpness\": \"round\",\n      \"boundElementIds\": [],\n      \"startBinding\": null,\n      \"endBinding\": null,\n      \"points\": [\n        [\n          0,\n          0\n        ],\n        [\n          7.680499844483396,\n          7.854738974308068\n        ],\n        [\n          14.737361275147578,\n          0.6676567128240549\n        ]\n      ],\n      \"lastCommittedPoint\": null,\n      \"startArrowhead\": null,\n      \"endArrowhead\": null\n    },\n    {\n      \"type\": \"text\",\n      \"version\": 711,\n      \"versionNonce\": 1424975585,\n      \"isDeleted\": false,\n      \"id\": \"sgbDSZlSFQp6K8OJxVCLH\",\n      \"fillStyle\": \"hachure\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 94.16010694073486,\n      \"y\": 221.67367245628827,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"transparent\",\n      \"width\": 168,\n      \"height\": 77,\n      \"seed\": 514223951,\n      \"groupIds\": [\n        \"rJ1P0XBbGfURJW4Zjp7X8\"\n      ],\n      \"strokeSharpness\": \"sharp\",\n      \"boundElementIds\": [],\n      \"fontSize\": 60.532407407407376,\n      \"fontFamily\": 1,\n      \"text\": \"Lorem\",\n      \"baseline\": 54,\n      \"textAlign\": \"left\",\n      \"verticalAlign\": \"top\"\n    },\n    {\n      \"type\": \"rectangle\",\n      \"version\": 848,\n      \"versionNonce\": 699203009,\n      \"isDeleted\": false,\n      \"id\": \"Fbr4J4GbUx_3cVnJZeDUR\",\n      \"fillStyle\": \"hachure\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 105.28096049574924,\n      \"y\": 777.3927948998587,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"#40c057\",\n      \"width\": 236.7746337205807,\n      \"height\": 129.787724922286,\n      \"seed\": 758115407,\n      \"groupIds\": [\n        \"jyeSNDETVrMfDjA684rmM\",\n        \"r185p5xk_gkQWscsbNK9f\",\n        \"02rK9i6fDrzb92TEA3yOv\"\n      ],\n      \"strokeSharpness\": \"sharp\",\n      \"boundElementIds\": [\n        \"KnOw0IqNapT66-Ld8k9YR\"\n      ]\n    },\n    {\n      \"type\": \"line\",\n      \"version\": 1021,\n      \"versionNonce\": 27583535,\n      \"isDeleted\": false,\n      \"id\": \"4rVM2st_hNvDNVeivFKJx\",\n      \"fillStyle\": \"hachure\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 151.91386823151265,\n      \"y\": 875.2471318282203,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"#40c057\",\n      \"width\": 148.11144963359644,\n      \"height\": 68.09092907653181,\n      \"seed\": 1867449377,\n      \"groupIds\": [\n        \"jyeSNDETVrMfDjA684rmM\",\n        \"r185p5xk_gkQWscsbNK9f\",\n        \"02rK9i6fDrzb92TEA3yOv\"\n      ],\n      \"strokeSharpness\": \"round\",\n      \"boundElementIds\": [],\n      \"startBinding\": null,\n      \"endBinding\": null,\n      \"points\": [\n        [\n          0,\n          2.790571850159554\n        ],\n        [\n          41.95525895647642,\n          -37.66300434880757\n        ],\n        [\n          77.85985467458359,\n          2.2434161645777104\n        ],\n        [\n          64.57235857289969,\n          -27.997918515902047\n        ],\n        [\n          101.18386346143059,\n          -65.0926776960784\n        ],\n        [\n          148.11144963359644,\n          2.9982513804534108\n        ]\n      ],\n      \"lastCommittedPoint\": null,\n      \"startArrowhead\": null,\n      \"endArrowhead\": null\n    },\n    {\n      \"type\": \"rectangle\",\n      \"version\": 778,\n      \"versionNonce\": 44956225,\n      \"isDeleted\": false,\n      \"id\": \"qXl4e48NAuUwzpEfhC29U\",\n      \"fillStyle\": \"hachure\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 106.81574772311251,\n      \"y\": 920.9971342596966,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"#868e96\",\n      \"width\": 130.4555714909401,\n      \"height\": 19.021351602145263,\n      \"seed\": 875268719,\n      \"groupIds\": [\n        \"r185p5xk_gkQWscsbNK9f\",\n        \"02rK9i6fDrzb92TEA3yOv\"\n      ],\n      \"strokeSharpness\": \"sharp\",\n      \"boundElementIds\": []\n    },\n    {\n      \"type\": \"rectangle\",\n      \"version\": 585,\n      \"versionNonce\": 1242489967,\n      \"isDeleted\": false,\n      \"id\": \"SCiYOb4RAPIz2fSU5DKLM\",\n      \"fillStyle\": \"hachure\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 89.6857180711695,\n      \"y\": 753.6173472093667,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"transparent\",\n      \"width\": 268.0068597560985,\n      \"height\": 201.0165539253049,\n      \"seed\": 732114913,\n      \"groupIds\": [\n        \"r185p5xk_gkQWscsbNK9f\",\n        \"02rK9i6fDrzb92TEA3yOv\"\n      ],\n      \"strokeSharpness\": \"sharp\",\n      \"boundElementIds\": []\n    },\n    {\n      \"type\": \"text\",\n      \"version\": 821,\n      \"versionNonce\": 2043826625,\n      \"isDeleted\": false,\n      \"id\": \"bBoCWgoltRNloJdihPVGO\",\n      \"fillStyle\": \"hachure\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 93.37413979508756,\n      \"y\": 666.4536843145472,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"transparent\",\n      \"width\": 165,\n      \"height\": 77,\n      \"seed\": 1065835247,\n      \"groupIds\": [\n        \"02rK9i6fDrzb92TEA3yOv\"\n      ],\n      \"strokeSharpness\": \"sharp\",\n      \"boundElementIds\": [],\n      \"fontSize\": 60.532407407407376,\n      \"fontFamily\": 1,\n      \"text\": \"Ipsum\",\n      \"baseline\": 54,\n      \"textAlign\": \"left\",\n      \"verticalAlign\": \"top\"\n    },\n    {\n      \"type\": \"rectangle\",\n      \"version\": 667,\n      \"versionNonce\": 1107587489,\n      \"isDeleted\": false,\n      \"id\": \"oMvMUo0ZpQmEpebj2REkQ\",\n      \"fillStyle\": \"cross-hatch\",\n      \"strokeWidth\": 2,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 38.59801190836333,\n      \"y\": 148.00331240794685,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"transparent\",\n      \"width\": 373.2520963004604,\n      \"height\": 809.9016393442624,\n      \"seed\": 1447379425,\n      \"groupIds\": [\n        \"n3hfdKnrbb5ZHY0FONQP7\"\n      ],\n      \"strokeSharpness\": \"sharp\",\n      \"boundElementIds\": []\n    },\n    {\n      \"type\": \"text\",\n      \"version\": 666,\n      \"versionNonce\": 602780911,\n      \"isDeleted\": false,\n      \"id\": \"sPR-fiqyX0vbWe-8W27y6\",\n      \"fillStyle\": \"cross-hatch\",\n      \"strokeWidth\": 2,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 51.29309477327297,\n      \"y\": 154.10610001787018,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"transparent\",\n      \"width\": 36,\n      \"height\": 21,\n      \"seed\": 219220143,\n      \"groupIds\": [\n        \"n3hfdKnrbb5ZHY0FONQP7\"\n      ],\n      \"strokeSharpness\": \"sharp\",\n      \"boundElementIds\": [],\n      \"fontSize\": 16,\n      \"fontFamily\": 1,\n      \"text\": \"10:47\",\n      \"baseline\": 15,\n      \"textAlign\": \"center\",\n      \"verticalAlign\": \"top\"\n    },\n    {\n      \"type\": \"rectangle\",\n      \"version\": 560,\n      \"versionNonce\": 581408129,\n      \"isDeleted\": false,\n      \"id\": \"yQOUIgBdSZsMqhvOw8ZGV\",\n      \"fillStyle\": \"cross-hatch\",\n      \"strokeWidth\": 2,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 366.6871986811875,\n      \"y\": 156.408620479991,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"transparent\",\n      \"width\": 33.92857142857156,\n      \"height\": 15.476190476190823,\n      \"seed\": 1323589057,\n      \"groupIds\": [\n        \"FsxbD2OyRu-7hD47wAU6q\",\n        \"n3hfdKnrbb5ZHY0FONQP7\"\n      ],\n      \"strokeSharpness\": \"sharp\",\n      \"boundElementIds\": []\n    },\n    {\n      \"type\": \"rectangle\",\n      \"version\": 664,\n      \"versionNonce\": 1835482895,\n      \"isDeleted\": false,\n      \"id\": \"sLEMzNR0pFFqFEkxLWwhj\",\n      \"fillStyle\": \"solid\",\n      \"strokeWidth\": 2,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 368.1752939192829,\n      \"y\": 161.17052524189376,\n      \"strokeColor\": \"transparent\",\n      \"backgroundColor\": \"#000\",\n      \"width\": 20.83333333333344,\n      \"height\": 8.33333333333394,\n      \"seed\": 1181358799,\n      \"groupIds\": [\n        \"FsxbD2OyRu-7hD47wAU6q\",\n        \"n3hfdKnrbb5ZHY0FONQP7\"\n      ],\n      \"strokeSharpness\": \"sharp\",\n      \"boundElementIds\": []\n    },\n    {\n      \"type\": \"draw\",\n      \"version\": 640,\n      \"versionNonce\": 2137687343,\n      \"isDeleted\": false,\n      \"id\": \"64RXhJMAZkGwTI7L-A64q\",\n      \"fillStyle\": \"cross-hatch\",\n      \"strokeWidth\": 2,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 138.53451445575956,\n      \"y\": 152.2220184429657,\n      \"strokeColor\": \"#000\",\n      \"backgroundColor\": \"#000\",\n      \"width\": 168.75,\n      \"height\": 21.875,\n      \"seed\": 857467119,\n      \"groupIds\": [\n        \"n3hfdKnrbb5ZHY0FONQP7\"\n      ],\n      \"strokeSharpness\": \"round\",\n      \"boundElementIds\": [],\n      \"points\": [\n        [\n          0,\n          0\n        ],\n        [\n          168.75,\n          0.78125\n        ],\n        [\n          139.0625,\n          21.09375\n        ],\n        [\n          27.34375,\n          21.875\n        ],\n        [\n          0,\n          0\n        ]\n      ],\n      \"lastCommittedPoint\": null,\n      \"startArrowhead\": null,\n      \"endArrowhead\": null\n    },\n    {\n      \"type\": \"arrow\",\n      \"version\": 287,\n      \"versionNonce\": 694697121,\n      \"isDeleted\": false,\n      \"id\": \"iaSrpzPWpzMSNMpXogYOp\",\n      \"fillStyle\": \"hachure\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 300.2017299107141,\n      \"y\": 850.6863141741071,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"#40c057\",\n      \"width\": 228.88645111224037,\n      \"height\": 0,\n      \"seed\": 96482177,\n      \"groupIds\": [],\n      \"strokeSharpness\": \"round\",\n      \"boundElementIds\": [],\n      \"startBinding\": null,\n      \"endBinding\": null,\n      \"points\": [\n        [\n          0,\n          0\n        ],\n        [\n          228.88645111224037,\n          0\n        ]\n      ],\n      \"lastCommittedPoint\": null,\n      \"startArrowhead\": \"arrow\",\n      \"endArrowhead\": null\n    },\n    {\n      \"type\": \"text\",\n      \"version\": 133,\n      \"versionNonce\": 430074047,\n      \"isDeleted\": false,\n      \"id\": \"4V7jTH73uhW9U3Mf4ka3V\",\n      \"fillStyle\": \"hachure\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 561.926321847098,\n      \"y\": 840.7475934709822,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"#40c057\",\n      \"width\": 551,\n      \"height\": 24,\n      \"seed\": 21666991,\n      \"groupIds\": [],\n      \"strokeSharpness\": \"sharp\",\n      \"boundElementIds\": [],\n      \"fontSize\": 20,\n      \"fontFamily\": 3,\n      \"text\": \"<img src=\\\"hills2.webp\\\" alt=\\\"Some green hills.\\\">\",\n      \"baseline\": 19,\n      \"textAlign\": \"left\",\n      \"verticalAlign\": \"top\"\n    },\n    {\n      \"type\": \"arrow\",\n      \"version\": 315,\n      \"versionNonce\": 838998305,\n      \"isDeleted\": false,\n      \"id\": \"BqZVK3p0Qi8MVVTElesxX\",\n      \"fillStyle\": \"hachure\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 300.8599330357142,\n      \"y\": 402.75516183035705,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"#40c057\",\n      \"width\": 245.2906145368304,\n      \"height\": 0,\n      \"seed\": 1864510241,\n      \"groupIds\": [],\n      \"strokeSharpness\": \"round\",\n      \"boundElementIds\": [],\n      \"startBinding\": null,\n      \"endBinding\": null,\n      \"points\": [\n        [\n          0,\n          0\n        ],\n        [\n          245.2906145368304,\n          0\n        ]\n      ],\n      \"lastCommittedPoint\": null,\n      \"startArrowhead\": \"arrow\",\n      \"endArrowhead\": null\n    },\n    {\n      \"type\": \"text\",\n      \"version\": 281,\n      \"versionNonce\": 25927775,\n      \"isDeleted\": false,\n      \"id\": \"FyPrZd2L6gRoOGq1nN3Ti\",\n      \"fillStyle\": \"hachure\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 566.0348859514507,\n      \"y\": 392.27359444754467,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"#40c057\",\n      \"width\": 527,\n      \"height\": 24,\n      \"seed\": 734155631,\n      \"groupIds\": [],\n      \"strokeSharpness\": \"sharp\",\n      \"boundElementIds\": [],\n      \"fontSize\": 20,\n      \"fontFamily\": 3,\n      \"text\": \"<img src=\\\"hills1.webp\\\" alt=\\\"Some red hills.\\\">\",\n      \"baseline\": 19,\n      \"textAlign\": \"left\",\n      \"verticalAlign\": \"top\"\n    },\n    {\n      \"type\": \"rectangle\",\n      \"version\": 73,\n      \"versionNonce\": 1823373263,\n      \"isDeleted\": false,\n      \"id\": \"rBE4FojLxgVv8_DdIp6Pq\",\n      \"fillStyle\": \"hachure\",\n      \"strokeWidth\": 4,\n      \"strokeStyle\": \"dashed\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 98.64547293526772,\n      \"y\": 767.8839285714286,\n      \"strokeColor\": \"#1864ab\",\n      \"backgroundColor\": \"transparent\",\n      \"width\": 252.71902901785717,\n      \"height\": 147.1575927734375,\n      \"seed\": 1347514945,\n      \"groupIds\": [],\n      \"strokeSharpness\": \"sharp\",\n      \"boundElementIds\": []\n    },\n    {\n      \"type\": \"arrow\",\n      \"version\": 328,\n      \"versionNonce\": 1316038063,\n      \"isDeleted\": false,\n      \"id\": \"KnOw0IqNapT66-Ld8k9YR\",\n      \"fillStyle\": \"hachure\",\n      \"strokeWidth\": 4,\n      \"strokeStyle\": \"dashed\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 350.6163366959029,\n      \"y\": 802.3288294936297,\n      \"strokeColor\": \"#1864ab\",\n      \"backgroundColor\": \"transparent\",\n      \"width\": 186.11135931414174,\n      \"height\": 161.6804208408505,\n      \"seed\": 776516143,\n      \"groupIds\": [],\n      \"strokeSharpness\": \"round\",\n      \"boundElementIds\": [],\n      \"startBinding\": {\n        \"elementId\": \"Fbr4J4GbUx_3cVnJZeDUR\",\n        \"focus\": 0.4184715711922294,\n        \"gap\": 8.56074247957298\n      },\n      \"endBinding\": {\n        \"elementId\": \"zhhvRKTI4FV3yDLcHzyB3\",\n        \"focus\": 0.9919794317120639,\n        \"gap\": 10.614536830357054\n      },\n      \"points\": [\n        [\n          0,\n          0\n        ],\n        [\n          186.11135931414174,\n          -161.6804208408505\n        ]\n      ],\n      \"lastCommittedPoint\": null,\n      \"startArrowhead\": \"arrow\",\n      \"endArrowhead\": null\n    },\n    {\n      \"type\": \"text\",\n      \"version\": 186,\n      \"versionNonce\": 1473842929,\n      \"isDeleted\": false,\n      \"id\": \"zhhvRKTI4FV3yDLcHzyB3\",\n      \"fillStyle\": \"hachure\",\n      \"strokeWidth\": 4,\n      \"strokeStyle\": \"dashed\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 547.3422328404016,\n      \"y\": 628.6583600725445,\n      \"strokeColor\": \"#1864ab\",\n      \"backgroundColor\": \"transparent\",\n      \"width\": 914,\n      \"height\": 24,\n      \"seed\": 2041159073,\n      \"groupIds\": [],\n      \"strokeSharpness\": \"sharp\",\n      \"boundElementIds\": [\n        \"KnOw0IqNapT66-Ld8k9YR\"\n      ],\n      \"fontSize\": 20,\n      \"fontFamily\": 3,\n      \"text\": \"https://example.org#:~:selector(type=CssSelector,value=img[src=\\\"hills2.webp\\\"])\",\n      \"baseline\": 19,\n      \"textAlign\": \"left\",\n      \"verticalAlign\": \"top\"\n    }\n  ],\n  \"appState\": {\n    \"gridSize\": null,\n    \"viewBackgroundColor\": \"#ffffff\"\n  }\n}\n"
  },
  {
    "path": "fragment-directive-api.md",
    "content": "# Fragment Directive API\n\n## Current Status\n\nAs of Oct 29, 2021: The API described below is available for experimentation in Chrome 97.0.4685.0 and newer behind a flag. Use `--enable-blink-features=TextFragmentAPI` to turn it on (or chrome://flags/#enable-experimental-web-platform-features which turns on all experimental features).\n\n## Introduction\n\nThis document proposes a programmatic API through which authors can interact with text (and future) directives.\n\nToday, when a page is loaded with a text directive such as `https://example.org#:~:text=foo,bar`, the author has no way[^1] to tell that a text directive was set or what text was highlighted. The fragment directive portion of the URL (everything in the fragment after and including `:~:`) is stripped from the URL when the document is loaded. This is done for two reasons:\n\n1. _Compatibility_ - Some pages assume the fragment will always be of an expected form or entirely absent. Without stripping the fragment directive, these pages may break with a user-supplied directive feature.\n\n2. _Privacy_ - Some directives may contain data that shouldn't be visible to page script. This isn't a concern for text directives since the directive will only contain content already on the page (and the page can tell where it's scrolled to). However, as an example, the [proposed](https://github.com/bokand/web-annotations/blob/main/URL-based-annotation.md) note directive uses the fragment directive to allow users to share comments with a friend. In that case, the destination page should not have access to the content.\n\nProviding a structured API allows the browser to expose enough information and functionality to enable authors to extend and customize how different directives behave without violating either of the above goals.\n\n[^1]: As noted in https://crbug.com/1096983, this is accidentally exposed via the performance API. This is a bug that we'd like to fix but some use cases are currently relying on this.\n\n## Use cases\n\n* Attach comments/responses to specific parts of text on a page - e.g. [Marginalia](https://indieweb.org/marginalia)\n\n* Enable pages to easily create text directive links. The rules for how text is matched are [necessarily complicated](https://wicg.github.io/scroll-to-text-fragment/#find-a-range-from-a-text-directive); they must consider word boundaries, DOM node display types and visibility, and various nuances of how DOM is traversed. This API allows an author to let the browser generate a valid text directive URL for a given Range.\n\n* Enable text directives in cross-origin iframes. To prevent [XS-Search attacks](https://wicg.github.io/scroll-to-text-fragment/#example-4d0b486d:~:text=A%20malicious%20page%20embeds%20a%20cross%2Dorigin%20victim%20in%20an%20iframe,its%20own%20document.), text directives are not applied when navigated from a cross-origin initiator. However, an iframe can navigate itself to a text directive. By allowing an embedder page to read the text directive, it can `postMessage()` it to a cross-origin document that's opted-in to this behavior, enabling deep linking to the inner frame (see examples section below).\n\n* Provide application specific helpful UI. E.g. a sublime like editor might highlight sections of the preview containing notes, or an application could provide an arrow that points to the fact that there are notes / text to be read further down, possibly also jumping to that note when clicked.\n\n## WebIDL\n\nThis is the IDL as implemented behind a flag in Chrome.\n\n```WebIDL\n// The following build on the existing but empty document.fragmentDirective\n// See https://wicg.github.io/scroll-to-text-fragment/#feature-detectability\n\n// === Current ===\n\n[Exposed=Window]\ninterface FragmentDirective {\n};\n\npartial interface Document {\n    [SameObject] readonly attribute FragmentDirective fragmentDirective;\n};\n\n// === Changes/Additions ===\n\n[Exposed=Window]\ninterface FragmentDirective {\n  // Array of parsed Directive objects, one for each term in the fragment\n  // directive (i.e. currently, each `text=` term)\n  readonly attribute FrozenArray<Directive> items;\n\n  // TODO: add(Directive)?\n\n  // Creates a SelectorDirective object that can be used to select the given\n  // range/selection.\n  Promise<SelectorDirective> createSelectorDirective(Range or Selection);\n };\n\nenum DirectiveType { \"text\" };\n\n// Interface common to all future Directive types.\n[Exposed=Window]\ninterface Directive {\n  readonly attribute DirectiveType type;\n  DOMString toString();\n  // TODO: remove()?\n}\n\n// Interface common to all selector Directive types (i.e. those that\n// scroll/indicate some sub-portion of the document).\n[Exposed=Window]\ninterface SelectorDirective : Directive {\n  Promise<Range> getMatchingRange();\n}\n\ndictionary TextDirectiveOptions {\n    DOMString prefix;\n    DOMString textStart;\n    DOMString textEnd;\n    DOMString suffix;\n};\n\n// TODO: [Serializable]\n[Exposed=Window]\ninterface TextDirective : SelectorDirective {\n  constructor(TextDirectiveOptions);\n  // TODO: constructor(DOMString directive_string);\n  readonly attribute DOMString prefix;\n  readonly attribute DOMString textStart;\n  readonly attribute DOMString textEnd;\n  readonly attribute DOMString suffix;\n};\n```\n\nWhy a `SelectorDirective` base-class, in addition to `Directive`? The [proposed](https://github.com/WICG/scroll-to-text-fragment/blob/main/EXTENSIONS.md#proposed-solution) CSS selector directive would behave very similarly to a text directive and allows `createSelectorDirective()` to return a `SelectorDirective`. OTOH, the proposed [note selector](https://github.com/bokand/web-annotations/blob/main/URL-based-annotation.md) would not fit this interface.\n\n_TODO: Maybe `SelectorDirective` is unnecessary? Callers could always determine the directive type using `Directive.type` if they need to. Also, it may actually make sense for `note` to provide `getMatchingRange()`...)_\n\n## Examples\n\n### Marginalia-like use cases:\n\n```JS\n// Coming from a server-side WebMention:\nconst comment_text = \"Great Point!\";\nconst comment_url = \"https://example.org/post.html#:~:text=My%20point\";\n\nconst directive_string = extractTextDirective(comment_url); // \"My%20point\";\n\nconst directive = new TextDirective(directive_string);\nconst range = await directive.getMatchingRange();\nattachCommentUI(comment_text, range);\n```\n\n### Generate a link for the user's selection\n\n```JS\ndocument.onselectionchange = () => {\n  const selection = document.getSelection();\n  const text_directive =\n      await document.fragmentDirective.createSelectorDirective(selection);\n  shareButton.onclick = () => {\n    const url = `${window.location.href}#:~:${text_directive.toString()}`;\n    navigator.clipboard.writeText(url);\n  };\n};\n```\n\n### Forward a text directive across origins\n\n```JS\n// Embedder document\nconst text_directives =\n    document.fragmentDirectives.items.filter(i => i.type === \"text\"));\n\nconst message = {\n  type: 'text-directives',\n  directives: text_directives;\n}\n\nframes[0].postMessage(message);\n```\n\nIn the cross-origin document:\n\n```JS\n//Embedee document\nwindow.onmessage = (e) => {\n  if (e.type === 'text-directives') {\n    const strings = e.directives.map(i => i.toString());\n    window.location.hash = `:~:${strings.join('&')}`;\n  }\n});\n```\n\n_TODO: setting `location.hash` isn't great. Consider adding `fragmentDirective.add(Directive)` and adding a `Directive.remove()`._\n\n## FragmentDirective.items\n\nThe `items` array reflects the currently active directives on the page. Using text directives as an example, an entry should exist in `items` for a text directive as long a highlight is showing. If the user dismisses the highlight, it is removed from the array. Conversely, if the directive is removed from `items` programmatically (see next section), the highlight should be removed from the page.\n\n## FragmentDirective as part of location.hash\n\nCurrently, script can add a directive by writing to `location.hash`:\n\n```JS\nlocation.hash = \":~:text=foo%20bar\";\n```\n\nThe snippet above will add a text directive to the page, highlighting \"foo bar\" and adding a `TextDirective` to `fragmentDirective.items`. However, this still runs the [fragment directive stripping steps](https://wicg.github.io/scroll-to-text-fragment/#process-and-consume-fragment-directive):\n\n```JS\nconst value = \":~:text=foo%20bar\";\nlocation.hash = value;\nconsole.log(location.hash);  // Output: \"\"\n```\n\nThis is rather unintuitive and surprising.\n\nThere's also the question of what happens to existing directives in `fragmentDirective.items` when the hash is modified. In the cases below, suppose the user navigated to `https://example.org/blog.html#:~:text=acme`.\n\n1. What should happen when script sets a hash with no fragment directive? (e.g. `location.hash = 'page1';`).\n2. What should happen when script sets a hash with an unrelated directive? (e.g. `location.hash = ':~:note(href=notes.example.org)';`)\n3. What should happen when script sets a hash with a text directive? (e.g. `location.hash = ':~:text=blog%20title';`)\n\nThat is, are changes to `location.hash` additive or do they replace existing directives?\n\nFor case 1, we almost certainly shouldn't affect existing directives as this would violate the _compatibility_ goal from the introduction. Pages often write to their hash for various reasons, these shouldn't interfere with user-supplied directives. That is, a page modifying its hash shouldn't remove text highlights.\n\nFor case 2, it also seems like we shouldn't remove the text directive. Directives of different types should behave independently. That is, adding an annotation to a page shouldn't clear text highlights.\n\nIn case 3, either behavior could work: a new highlight should be added and the existing one kept OR the new highlight replaces all existing ones. Though, if additive, it means there's no way to remove directives.\n\nAnother consideration: _Given that a page can add new directives, there should be a way to remove existing ones_. Using `location.hash` for this will necessarily lead to violating our intuition for how at least one of the above cases works.\n\n### Proposed Behavior\n\nManaging directives using `location.hash` leads to complicated, difficult-to-explain behaviors. Let's remove fragment directive processing from `location.hash` and add explicit APIs for doing this. E.g.\n\n```JS\n// Add a directive to the page\ndocument.fragmentDirective.add(new TextDirective(\"foo%20bar\"));\ndocument.fragmentDirective.add(new TextDirective(\"second%20highlight\"));\n\n// Remove a directive\ndocument.fragmentDirective.items[1].remove();\n// Perhaps document.fragmentDirective.clear()?\n```\n\nSetting location.hash affects only the part of the fragment that isn't the fragment directive. E.g.\n\n```JS\nlocation.hash = ':~:text=foo%20bar';\nconsole.log(location.hash);  // Output: \"%3A%7E%3Atext=foo%20bar\"\n```\n\nThat is, setting a directive delimiter in `location.hash` percent-encodes it so that it doesn't turn into fragment directive.\n\nThe same behavior is used whenever a same-document navigation occurs:\n\n```JS\nconsole.log(location.href);  // Output: \"https://example.com\";\nlocation = \"https://example.com#:~:text=foo%20bar\";\nconsole.log(location.href):  // Output: \"https://example.com%3A%7E%3Atext=foo%20bar\"\n```\n\nIn spec language: fragment directive processing from the URL occurs only when [navigating across documents](https://html.spec.whatwg.org/#navigating-across-documents).\n"
  },
  {
    "path": "index.bs",
    "content": "<pre class='metadata'>\nStatus: CG-DRAFT\nTitle: URL Fragment Text Directives\nED: https://wicg.github.io/scroll-to-text-fragment/\nShortname: text-directive\nLevel: 1\nEditor: Nick Burris, Google https://www.google.com, nburris@chromium.org\nEditor: David Bokan, Google https://www.google.com, bokan@chromium.org\nAbstract: Text directives add support for specifying a text snippet in the URL\n    fragment. When navigating to a URL with such a fragment, the user agent\n    can quickly emphasise and/or bring it to the user's attention.\nGroup: wicg\nRepository: wicg/scroll-to-text-fragment\nMarkup Shorthands: markdown yes\nWPT Display: inline\n</pre>\n\n<pre class='link-defaults'>\nspec:css-cascade-5; type:dfn; text:computed value\nspec:css-display-3; type:value; for:display; text:flex\nspec:css-display-3; type:value; for:display; text:grid\nspec:css-display-4; type:property; text:display\nspec:css-display-4; type:property; text:visibility\nspec:dom; type:dfn; for:/; text:element\nspec:dom; type:dfn; for:range; text:end\nspec:dom; type:dfn; for:range; text:start\nspec:dom; type:dfn; text:parent element\nspec:dom; type:dfn; text:range\nspec:html; type:element; text:link\nspec:html; type:element; text:script\nspec:html; type:element; text:style\nspec:url; type:dfn; text:fragment\n</pre>\n\n<pre class=\"anchors\">\nspec:html; type:dfn; for:browsing context; text:group; url: https://html.spec.whatwg.org/multipage/browsers.html#tlbc-group\nspec:html; type:dfn; for:/; text:navigable; url: https://html.spec.whatwg.org/multipage/document-sequences.html#navigable\nspec:html; type:dfn; for:/; text:origin; url: https://html.spec.whatwg.org/multipage/browsers.html#concept-origin\nspec:html; type:dfn; text:user navigation involvement; url: https://html.spec.whatwg.org/multipage/browsing-the-web.html#user-navigation-involvement\nspec:html; type:dfn; for:document state; text:initiator origin; url: https://html.spec.whatwg.org/multipage/browsing-the-web.html#document-state-initiator-origin\nspec:html; type:dfn; for:/; text:document state; url: https://html.spec.whatwg.org/multipage/browsing-the-web.html#she-document-state\nspec:html; type:dfn; for:she; text:document; url: https://html.spec.whatwg.org/multipage/browsing-the-web.html#she-document\n</pre>\n\n<pre class=\"biblio\">\n  {\n    \"document-policy\": {\n      \"authors\": [\n        \"Ian Clelland\"\n      ],\n      \"href\": \"https://wicg.github.io/document-policy\",\n      \"title\": \"Document Policy\",\n      \"status\": \"ED\",\n      \"publisher\": \"W3C\",\n      \"deliveredBy\": [\n        \"https://www.w3.org/2011/webappsec/\"\n      ]\n    },\n    \"fetch-metadata\": {\n      \"authors\": [\n        \"Mike West\"\n      ],\n      \"href\": \"https://w3c.github.io/webappsec-fetch-metadata/\",\n      \"title\": \"Fetch Metadata Request Headers\",\n      \"status\": \"WD\",\n      \"publisher\": \"W3C\",\n      \"deliveredBy\": [\n        \"https://www.w3.org/TR/fetch-metadata/\"\n      ]\n    }\n  }\n</pre>\n\n<style>\n  .monkeypatch {\n    color: grey;\n  }\n\n  .monkeypatch .diff {\n    color: var(--text);\n  }\n</style>\n\n<h2 id=infrastructure>Infrastructure</h2>\n\n<p>This specification depends on the Infra Standard. [[!INFRA]]\n\n# Introduction # {#introduction}\n\n<div class='note'>This section is non-normative</div>\n\n## Use cases ## {#use-cases}\n\n### Web text references ### {#web-text-references}\nThe core use case for text fragments is to allow URLs to serve as an exact text\nreference across the web. For example, Wikipedia references could link to the\nexact text they are quoting from a page. Similarly, search engines can serve\nURLs that direct the user to the answer they are looking for in the page rather\nthan linking to the top of the page.\n\n### User sharing ### {#user-sharing}\nWith text directives, browsers may implement an option to 'Copy URL to here'\nwhen the user opens the context menu on a text selection. The browser can then\ngenerate a URL with the text selection appropriately specified, and the\nrecipient of the URL will have the specified text conveniently indicated.\nWithout text fragments, if a user wants to share a passage of text from a page,\nthey would likely just copy and paste the passage, in which case the receiver\nloses the context of the page.\n\n## Link Lifetime ## {#link-lifetime}\n\nThis specification attempts to maximize the useful lifetime of text directive links, for example, by\nusing the actual text content as the URL payload, and allowing a fallback element-id fragment.\nHowever, pages on the web often update and change their content. As such, links like this may \"rot\"\nin that the text content they point to no longer exists on the destination page.\n\nText directive links can be useful despite this problem. In user sharing use cases, the link is\noften transient, intended to be used only within a short time of sending. For longer duration use\ncases, such as references and web page links, text directives are still valuable since they degrade\ngracefully into an ordinary link. Additionally, the presence of a stale text directive can be useful\ninformation to surface to a user, to help them understand the link creator's original intent and\nthat the page content may have changed since the link was created.\n\nSee [[#generating-text-fragment-directives]] for best practices on how to create robust text\ndirective links.\n\n# Description # {#description}\n\n## Indication ## {#indication}\n\n<div class='note'>This section is non-normative</div>\n\nThis specification intentionally doesn't define what actions a user agent takes\nto \"indicate\" a text match. There are different experiences and trade-offs a\nuser agent could make. Some examples of possible actions:\n\n* Providing visual emphasis or highlight of the text passage\n* Automatically scrolling the passage into view when the page is navigated\n* Activating a UA's find-in-page feature on the text passage\n* Providing a \"Click to scroll to text passage\" notification\n* Providing a notification when the text passage isn't found in the page\n\n<div class='note'>\nThe choice of action can have implications for user security and privacy.  See\nthe [[#security-and-privacy]] section for details.\n</div>\n\n## Syntax ## {#syntax}\n\n<div class='note'>This section is non-normative</div>\n\nA [=text directive=] is specified in the [=/fragment directive=] (see\n[[#the-fragment-directive]]) with the following format:\n<pre>\n#:~:text=[prefix-,]start[,end][,-suffix]\n          context  |--match--|  context\n</pre>\n<em>(Square brackets indicate an optional parameter)</em>\n\nThe text parameters are percent-decoded before matching. Dash (-), ampersand\n(&), and comma (,) characters in text parameters are percent-encoded to avoid\nbeing interpreted as part of the text directive syntax.\n\nThe only required parameter is <code>start</code>. If only <code>start</code> is specified, the\nfirst instance of this exact text string is the target text.\n\n<div class=\"example\">\n<code>#:~:text=an%20example%20text%20fragment</code> indicates that the\nexact text \"an example text fragment\" is the target text.\n</div>\n\nIf the <code>end</code> parameter is also specified, then the text directive refers to a\nrange of text in the page. The target text range is the text range starting at\nthe first instance of <code>start</code>, until the first instance of <code>end</code> that\nappears after <code>start</code>. This is equivalent to specifying the entire text range\nin the <code>start</code> parameter, but allows the URL to avoid being bloated with a\nlong text directive.\n\n<div class=\"example\">\n<code>#:~:text=an%20example,text%20fragment</code> indicates that the first\ninstance of \"an example\" until the following first instance of \"text fragment\"\nis the target text.\n</div>\n\n### Context Terms ### {#context-terms}\n\n<div class='note'>This section is non-normative</div>\n\nThe other two optional parameters are context terms. They are specified by the\ndash (-) character succeeding the prefix and preceding the suffix, to\ndifferentiate them from the <code>start</code> and <code>end</code> parameters, as any\ncombination of optional parameters can be specified.\n\nContext terms are used to disambiguate the target text fragment. The context\nterms can specify the text immediately before (prefix) and immediately after\n(suffix) the text fragment, allowing for whitespace.\n\n<div class=\"note\">\nWhile a match succeeds only if the context terms surround the target text\nfragment, any amount of whitespace is allowed between context terms and the text\nfragment. This allows context terms to cross element boundaries, for example if\nthe target text fragment is at the beginning of a paragraph and needs\ndisambiguation by the previous element's text as a prefix.\n</div>\n\nThe context terms are not part of the targeted text fragment and are not\nvisually indicated.\n\n<div class=\"example\">\n<code>#:~:text=this%20is-,an%20example,-text%20fragment</code> would match\nto \"an example\" in \"this is an example text fragment\", but not match to \"an\nexample\" in \"here is an example text\".\n</div>\n\n### BiDi Considerations ### {#bidi-considerations}\n\n<div class='note'>This section is non-normative</div>\n\n<div class='note'>\n  See <a\n  href=\"https://www.w3.org/International/articles/inline-bidi-markup/uba-basics.en\">Unicode\n  Bidirectional Algorithm basics</a> for a good overview of how Bidirectional\n  text works.\n</div>\n\nSince URL strings are ASCII encoded, they provide no built-in support for\nbi-directional text. However, the content that we wish to target on a page can\nbe LTR (left-to-right), RTL (right-to-left) or both (Bidirectional/BiDi). This\nsection provides an intuitive description the behavior implicitly described by\nthe normative sections further in this spec.\n\nThe characters of each term in the text fragment are in <em>logical order</em>,\nthat is, the order in which a native reader would read them in (and also the\norder in which characters are stored in memory).\n\nSimilarly, the <code>prefix</code> and <code>start</code> terms identify\ntext coming before another term in logical order, while <code>suffix</code> and\n<code>end</code> follow other terms in logical order.\n\nNote: user agents can visually render URLs in a manner friendlier to a native\nreader, for example, by converting the displayed string to Unicode. However, the\nstring representation of a URL remains plain ASCII characters.\n\n<div class=\"example\">\n  Suppose we want to select the text <code lang=\"ar\">مِصر‎</code> (Egypt, in Arabic),\n  that's preceeded by <code lang=\"ar\">البحرين‎</code> (Bahrain, in Arabic). We would\n  first percent encode each term:\n\n  <code lang=\"ar\">مِصر‎</code> becomes \"%D9%85%D8%B5%D8%B1\" (Note: UTF-8 character\n  [0xD9,0x85] is the first (right-most) character of the Arabic word.)\n\n  <code lang=\"ar\">البحرين‎</code> becomes \"%D8%A7%D9%84%D8%A8%D8%AD%D8%B1%D9%8A%D9%86\"\n\n  The text fragment would then become:\n\n  <code>\n    :~:text=%D8%A7%D9%84%D8%A8%D8%AD%D8%B1%D9%8A%D9%86-,%D9%85%D8%B5%D8%B1\n  </code>\n\n  When displayed in a browser's address bar, the browser can visually render the\n  text in its natural RTL direction, appearing to the user:\n\n  <code>\n    :~:text=<span lang=\"ar\">البحرين</span>-,<span lang=\"ar\">مِصر</span>\n  </code>\n</div>\n\n## The Fragment Directive ## {#the-fragment-directive}\n\nTo avoid compatibility issues with usage of existing URL fragments, this spec\nintroduces the concept of a <dfn>fragment directive</dfn>. It is the portion of\nthe URL [=url/fragment=] that follows the [=fragment directive delimiter=] and\nmay be null if the delimiter does not appear in the fragment.\n\nThe <dfn>fragment directive delimiter</dfn> is the string \":~:\", that is the\nthree consecutive code points U+003A (:), U+007E (~), U+003A (:).\n\n<div class=\"note\">\n  The [=fragment directive=] is part of the URL fragment. This means it\n  always appears after a U+0023 (#) code point in a URL.\n</div>\n\n<div class=\"example\">\n  To add a [=fragment directive=] to a URL like https://example.com, a fragment\n  is first appended to the URL: https://example.com#:~:text=foo.\n</div>\n\nThe fragment directive is parsed and processed into individual\n<dfn>directives</dfn>, which are instructions to the user agent to perform some\naction. Multiple directives may appear in the fragment directive.\n\n<div class=\"note\">\n  The only directive introduced in this spec is the text directive but others\n  could be added in the future.\n</div>\n\n<div class=\"example\">\n  <code>https://example.com#:~:text=foo&text=bar&unknownDirective</code>\n  <p>Contains 2 text directives and one unknown directive.</p>\n</div>\n\nTo prevent impacting page operation, it is stripped from script-accessible APIs to prevent\ninteraction with author script. This also ensures future directives can be added without web\ncompatibility risk.\n\n### Extracting the fragment directive ### {#extracting-the-fragment-directive}\n\nThis section describes the mechanism by which the fragment directive is hidden\nfrom script and how it fits into [[HTML#navigation-and-session-history]].\n\n<div class=\"note\">\n  The summarized changes in this section:\n\n  * Session history entries now include a new \"directive state\" item\n  * All new entries are created with a directive state with an empty value. If the new URL includes\n      a fragment directive it will be written to the state's value (otherwise it remains null).\n  * Any time a URL potentially including a fragment directive is written to a session history entry,\n      extract the fragment directive from the URL and store it in a directive state item of the\n      entry. There are four such points where a URL can potentially include a directive:\n      * In the \"navigate\" steps for typical cross-document navigations\n      * In the \"navigate to a fragment\" steps for fragment based same-document navigations\n      * In the \"URL and history update steps\" for synchronous updates such as\n          pushState/replaceState.\n      * In the \"create navigation params by fetching\" steps for URLs coming from a redirect.\n  * Same-document navigations that change only the fragment, and the new URL doesn't specify a\n      directive, will create an entry whose directive state refers to the previous entry's directive\n      state.\n\n</div>\n\nIn [[HTML#session-history-infrastructure]], define [=/directive state=]:\n\n>   <strong>Monkeypatching [[HTML#session-history-infrastructure]]:</strong>\n>\n>   <dfn>directive state</dfn> holds the value of the [=fragment directive=] at the time the session\n>   history entry was created and is used to invoke directives, such as text highlighting, whenever\n>   the entry is traversed. It has:\n>   * <dfn for=\"directive state\">value</dfn>, the [=fragment directive=] [=ASCII string=] or null,\n>       initially null.\n>\n>   A [=/directive state=] may be shared by multiple session history entries.\n>\n>   <div class=\"note\">\n>       <p>The fragment directive is removed from the URL before the URL is set to the session\n>       history entry. It is instead stored in the directive state. This prevents it from being\n>       visible to script APIs so that a directive can be specified without interfering with a\n>       page's operation.</p>\n>\n>       <p>The fragment directive is stored in the directive state object, rather than a raw string,\n>       since the same directive state can be shared across multiple contiguous session history\n>       entries. On a traversal, the directive is only processed (i.e. search text and highlight) if\n>       the directive state has changed between two entries.</p>\n>   </div>\n\nTo the definition of <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#session-history-entry\">session history entry</a>, add:\n\n>   <strong>Monkeypatching [[HTML#session-history-entries]]:</strong>\n>\n>   <div class=\"monkeypatch\">A session history entry is a struct with the following items:\n>     * ...\n>     * persisted user state, which is implementation-defined, initially null\n>     * <span class=\"diff\"><dfn for=she>directive state</dfn>, a [=/directive state=],\n>         initially a new [=/directive state=]</span>\n>   </div>\n\nAdd a helper algorithm for removing and returning a fragment directive string from a [=/URL=]:\n\n>   <strong>Monkeypatching [[HTML]]:</strong>\n>\n>   <div class=\"note\">\n>     This algorithm makes a URL's fragment end at the [=fragment directive\n>     delimiter=]. The returned [=/fragment directive=] includes all characters that follow the\n>     delimiter but does not include the delimiter.\n>   </div>\n>\n>   <div class=\"issue\">\n>     TODO: If a URL's fragment ends with ':~:' (i.e. empty directive), this will return null which\n>     is treated as the URL not specifying an explicit directive (and avoids clobbering an existing\n>     one. But maybe in this case we should return the empty string? That way a page can explicitly\n>     clear directives/highlights by navigating/pushState to '#:~:'.\n>   </div>\n>\n>   To <dfn>remove the fragment directive</dfn> from a [=/URL=] |url|, run these steps:\n>   1. Let |raw fragment| be equal to |url|'s [=url/fragment=].\n>   1. Let |fragment directive| be null.\n>   1. If |raw fragment| is non-null and contains the [=fragment directive delimiter=] as a\n>       substring:\n>       1. Let |position| be the [=string/position variable=] pointing to the first code\n>           point of the first instance, if one exists, of the [=fragment directive delimiter=] in\n>           |raw fragment|, or past the end of |raw fragment| otherwise.\n>       1. Let |new fragment| be the [=code point substring by positions=] of |raw fragment| from\n>           the start of |raw fragment| to |position|.\n>       1. Advance |position| by the [=string/code point length=] of the [=fragment directive\n>           delimiter=].\n>       1. If |position| does not point past the end of |raw fragment|:\n>           1. Set |fragment directive| to the [=code point substring to the end of the string=]\n>               |raw fragment| starting from |position|\n>       1. Set |url|'s [=url/fragment=] to |new fragment|.\n>   1. Return |fragment directive|.\n>\n>   <div class=\"example\">\n>      <code>https://example.org/#test:~:text=foo</code> will be parsed such that\n>      the fragment is the string \"test\" and the [=/fragment directive=] is the string\n>      \"text=foo\".\n>   </div>\n\nThe next four monkeypatches modify the creation of a session history entry, where the URL might\ncontain a fragment directive, to remove the fragment directive and store it in the [=/directive\nstate=].\n\nIn the definition of [=navigate=]:\n\n>   <strong>Monkeypatching [[HTML#beginning-navigation]]:</strong>\n>\n>   <div class=\"monkeypatch\">To navigate a navigable navigable to a URL |url|...:\n>     1. ...\n>         <li value=\"14\">Set navigable's ongoing navigation to navigationId.</li>\n>     15. If url's scheme is \"javascript\", then...\n>     16. In parallel, run these steps:\n>         1. ...\n>             <li value=\"5\">If url is about:blank, then set documentState's origin to documentState's initiator origin.</li>\n>         6. Otherwise, if url is about:srcdoc, then set documentState's origin to navigable's parent's active document's origin.\n>         7. <strike>Let historyEntry be a new session history entry, with its URL set to url and\n>             its document state set to documentState.</strike>\n>             <li value=\"7\"><span class=\"diff\">Let |fragment directive| be the result of running [=remove the\n>             fragment directive=] on |url|.</span></li>\n>         8. <span class=\"diff\">Let |directive state| be a new [=/directive\n>             state=] with [=directive state/value=] set to |fragment directive|.</span>\n>         9. <span class=\"diff\">Let historyEntry be a new session history entry, with its URL\n>             set to |url|, its document state set to documentState, and its [=she/directive state=]\n>             set to |directive state|.</span>\n>         10. Let navigationParams be null.\n>         11. ...\n>   </div>\n\nIn the definition of <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate-fragid\">navigate to a fragment</a>:\n\n>   <strong>Monkeypatching [[HTML#scroll-to-fragid]]:</strong>\n>\n>   <div class=\"monkeypatch\">To navigate to a fragment given navigable |navigable|, ...:\n>     1. <span class=\"diff\">Let |directive state| be navigable's active session history\n>         entry's [=she/directive state=].</span>\n>     1. <span class=\"diff\">Let |fragment directive| be the result of running\n>         [=remove the fragment directive=] on |url|.</span>\n>     1. <span class=\"diff\">If |fragment directive| is not null:</span>\n>         <div class=\"note\">Otherwise, when only the fragment has changed and it did not specify\n>         a directive, the active entry's directive state is reused. This prevents a fragment\n>         change from clobbering highlights.</div>\n>         1. <span class=\"diff\">Let |directive state| be a new [=/directive state=] with\n>             [=directive state/value=] set to |fragment directive|.\n>     2. Let historyEntry be a new session history entry, with\n>         * URL url\n>         * document state navigable's active session history entry's document state\n>         * scroll restoration mode navigable's active session history entry's scroll restoration\n>             mode\n>         * <span class=\"diff\">[=she/directive state=] |directive state|</span>\n>     2. Let entryToReplace be navigable's active session history entry if historyHandling is\n>         \"replace\", otherwise null.\n>     3. ...\n>   </div>\n\nIn the definition of <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#url-and-history-update-steps\">URL and history update steps</a>:\n\n>   <strong>Monkeypatching [[HTML#navigate-non-frag-sync]]:</strong>\n>\n>   <div class=\"monkeypatch\">The URL and history update steps, given a Document |document|, ...:\n>     1. Let |navigable| be |document|'s node navigable.\n>     2. Let |activeEntry| be |navigable|'s active session history entry.\n>     3. <span class=\"diff\">Let |fragment directive| be the result of running [=remove the\n>         fragment directive=] on |newUrl|.</span>\n>     5. Let |historyEntry| be a new session history entry, with\n>         * URL |newUrl|\n>         * ...\n>         * <span class=\"diff\">[=she/directive state=] |activeEntry|'s [=she/directive\n>             state=]</span>\n>     6. If |document|'s is initial about:blank is true, then set historyHandling to \"replace\".\n>     7. If historyHandling is \"push\", then:\n>         1. Increment document's history object's index.\n>         2. Set document's history object's length to its index + 1.\n>         3. <span class=\"diff\">If |newUrl| does not equal |activeEntry|'s URL with exclude\n>             fragments set to true OR |fragment directive| is not null, then:</span>\n>             <div class=\"note\">Otherwise, when only the fragment has changed and it did not specify\n>             a directive, the active entry's directive state is reused. This prevents a fragment\n>             change from clobbering highlights.</div>\n>             1. <span class=\"diff\">Let |historyEntry|'s [=she/directive state=] be a new\n>                 [=/directive state=] with [=directive state/value=] set to |fragment\n>                 directive|.</span>\n>     8. <span class=\"diff\">Otherwise, if |fragment directive| is not null, set\n>         |historyEntry|'s [=she/directive state=]'s [=directive state/value=] to |fragment\n>         directive|.</span>\n>     9. If serializedData is not null, then restore the history object state given document and\n>         newEntry.\n>   </div>\n\nIn the definition of <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#create-navigation-params-by-fetching\">\ncreate navigation params by fetching</a>:\n\n>   <strong>Monkeypatching [[HTML#populating-a-session-history-entry]]:</strong>\n>\n>   <div class=\"monkeypatch\">To create navigation params by fetching given a session history entry\n>       |entry|, ...:\n>     1. Assert: this is running in parallel.\n>     1. ...\n>         <li value=\"17\">Let currentURL be request's current URL.</li>\n>     1. Let commitEarlyHints be null.\n>     1. While true:\n>         1. If request's reserved client is not null and currentURL's origin is not the same as request's reserved client's creation URL's origin, then:\n>         1. ...\n>             <li value=\"21\">Set currentURL to |locationURL|.</li>\n>         1. <span class=\"diff\">Let |fragment directive| be the result of running\n>             [=remove the fragment directive=] on |locationURL|.</span>\n>         1. <strike class=\"diff\">Set |entry|'s URL to currentURL.</strike>\n>         1. <span class=\"diff\">Set |entry|'s URL to |locationURL|.</span>\n>         1. <span class=\"diff\">Set |entry|'s [=she/directive state=]'s [=directive state/value=] to\n>             |fragment directive|.\n>         1. If |locationURL| is a URL whose scheme is not a fetch scheme, then return a new non-fetch\n>             scheme navigation params, with initiator origin request's current URL's origin\n>         1. ...\n>   </div>\n\n<div class=\"note\">\n  <p>\n    Since a Document is populated from a history entry, its [=Document/URL=] will not include the\n    fragment directive. Similarly, since a window's {{Location}} object is a representation of the\n    [=/URL=] of the [=active document=], all getters on it will show a fragment-directive-stripped\n    version of the URL.\n  </p>\n\n  <p>\n    Additionally, since the {{HashChangeEvent}} is\n    <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#updating-the-document\">\n    fired in response to a changed fragment</a> between URLs of session history entries,\n    <code>hashchange</code> will not be fired if a navigation or traversal changes only the fragment\n    directive.\n  </p>\n\n  <p>\n    Some examples are provided to help clarify various edge cases.\n  </p>\n</div>\n\n<div class=\"example\">\n  ```\n  window.location = \"https://example.com#page1:~:hello\";\n  console.log(window.location.href); // 'https://example.com#page1'\n  console.log(window.location.hash); // '#page1'\n  ```\n\n  The initial navigation created a new session history entry. The entry's URL is stripped of the\n  fragment directive: \"https://example.com#page1\". The entry's directive state value is set to\n  \"hello\". Since the document is populated from the entry, web APIs don't include the fragment\n  directive in URLs.\n\n  ```\n  location.hash = \"page2\";\n  console.log(location.href); // 'https://example.com#page2'\n  ```\n\n  A same document navigation changed only the fragment. This adds a new session history entry in the\n  <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate-fragid\">navigate to\n  a fragment</a> steps. However, since only the fragment changed, the new entry's directive state\n  points to the same state as the first entry, with a value of \"bar\".\n\n  ```\n  onhashchange = () => console.assert(false, \"hashchange doesn't fire.\");\n  location.hash = \"page2:~:world\";\n  console.log(location.href); // 'https://example.com#page2'\n  onhashchange = null;\n  ```\n\n  A same document navigation changes only the fragment but includes a fragment directive. Since an\n  explicit directive was provided, the new entry includes its own directive state with a value of\n  \"fizz\".\n\n  The hashchange event is not fired since the page-visible fragment is unchanged; only the fragment\n  directive changed. This is because the comparison for hashchange is done on the URLs in the\n  session history entries, where the fragment directive has been removed.\n\n  ```\n  history.pushState(\"\", \"\", \"page3\");\n  console.log(location.href); // 'https://example.com/page3'\n  ```\n\n  pushState creates a new session history entry for the same document. However, since the\n  non-fragment URL has changed, this entry has its own directive state with value currently null.\n</div>\n\n<div class=\"example\">\n  In other cases where a URL is not set to a session history entry, there is no\n  fragment directive stripping.\n\n  For URL objects:\n\n  ```\n  let url = new URL('https://example.com#foo:~:bar');\n  console.log(url.href); // 'https://example.com#foo:~:bar'\n  console.log(url.hash); // '#foo:~:bar'\n\n  document.url = url;\n  console.log(document.url.href); // 'https://example.com#foo:~:bar'\n  console.log(document.url.hash); // '#foo:~:bar'\n\n  ```\n\n  The `<a>` or `<area>` elements:\n\n  ```\n  <a id='anchor' href=\"https://example.com#foo:~:bar\">Anchor</a>\n  <script>\n    console.log(anchor.href); // 'https://example.com#foo:~:bar'\n    console.log(anchor.hash); // '#foo:~:bar'\n  </script>\n  ```\n</div>\n\n### Applying directives to a document ### {#applying-directives-to-a-document}\n\nThe section above described how the [=fragment directive=] is separated from the URL and stored in a\nsession history entry.\n\nThis section defines how and when navigations and traversals make use of history entry's [=she/directive\nstate=] to apply the directives associated with a session history entry to a [=/Document=].\n\n>   <strong>Monkeypatching [[DOM#interface-document]]:</strong>\n>\n>   Each document has an associated <dfn for=\"Document\">pending text directives</dfn> which is either\n>   null or an <a spec=infra>list</a> of [=text directives=]. It is initially null.\n\nIn the definition of <a spec=\"HTML\">update document for history step application</a>:\n\n>   <strong>Monkeypatching [[HTML#updating-the-document]]:</strong>\n>\n>   <div class=\"monkeypatch\">To update document for history step application given a Document\n>   |document|, a session history entry |entry|,...\n>     1. ...\n>         <li value=\"4\">Set |document|'s history object's length to scriptHistoryLength</li>\n>     5. If <var ignore>documentsEntryChanged</var> is true, then:\n>         1. Let <var ignore>oldURL</var> be |document|'s latest entry's URL.\n>         2. <div class=\"diff\">If |document|'s latest entry's [=she/directive state=] is not\n>             |entry|'s [=she/directive state=] then:\n>             1. Let |fragment directive| be |entry|'s [=she/directive state=]'s\n>                 [=directive state/value=].\n>             1. Set |document|'s [=Document/pending text directives=] to the result of [=parse the\n>                 fragment directive|parsing=] |fragment directive|.\n>                 </div>\n>         3. Set |document|'s latest entry to |entry|\n>         4. ...\n>   </div>\n\n### Fragment directive grammar ### {#fragment-directive-grammar}\n\nNote: This section is non-normative.\n\nNote: This grammar is provided as a convenient reference; however, the rules and steps for parsing\nare specified imperatively in the [[#text-directives]] section. Where this grammar differs in\nbehavior from the steps of that section, the steps there are to be taken as the authoritative source\nof truth.\n\nThe [=FragmentDirective=] can contain multiple directives split by the \"&\" character. Currently this\nmeans we allow multiple text directives to enable multiple indicated strings in the page, but this\nalso allows for future directive types to be added and combined. For extensibility, we do not fail\nto parse if an unknown directive is in the &-separated list of directives.\n\nA <a spec=infra>string</a> is a valid fragment directive if it matches the EBNF (Extended\nBackus-Naur Form) production:\n\n<dl>\n  <dt>\n    <dfn id=\"fragmentdirectiveproduction\">`FragmentDirective`</dfn> `::=`\n  </dt>\n  <dd>\n    <code>([=TextDirective=] | [=UnknownDirective=]) (\"&\" [=FragmentDirective=])?</code>\n  </dd>\n  <dt>\n    <dfn>`TextDirective`</dfn> `::=`\n  </dt>\n  <dd>\n    <code>\"text=\"[=CharacterString=]</code>\n  </dd>\n  <dt>\n    <dfn>`UnknownDirective`</dfn> `::=`\n  </dt>\n  <dd>\n    <code>[=CharacterString=] - [=TextDirective=]</code>\n  </dd>\n  <dt>\n    <dfn>`CharacterString`</dfn> `::=`\n  </dt>\n  <dd>\n    <code>([=ExplicitChar=] | [=PercentEncodedByte=])*</code>\n  </dd>\n  <dt>\n    <dfn>`ExplicitChar`</dfn> `::=`\n  </dt>\n  <dd>\n    <code>[a-zA-Z0-9] | \"!\" | \"$\" | \"'\" | \"(\" | \")\" | \"*\" | \"+\" | \".\" | \"/\" | \":\" |\n    \";\" | \"=\" | \"?\" | \"@\" | \"_\" | \"~\" | \",\" | \"-\"</code>\n  <div class = \"note\">\n    An [=ExplicitChar=] may be any [=URL code point=] other than \"&\".\n  </div>\n  </dd>\n</dl>\n\nA [=TextDirective=] is considered valid if it matches the following production:\n\n<dl>\n  <dt><dfn>`ValidTextDirective`</dfn> `::=`</dt>\n  <dd><code>\"text=\" [=TextDirectiveParameters=]</code></dd>\n  <dt><dfn>`TextDirectiveParameters`</dfn> `::=`</dt>\n  <dd>\n    <code>\n    ([=TextDirectivePrefix=] \",\")? [=TextDirectiveString=]\n    (\",\" [=TextDirectiveString=])?  (\",\" [=TextDirectiveSuffix=])?\n    </code>\n  </dd>\n  <dt><dfn>`TextDirectivePrefix`</dfn> `::=`</dt>\n  <dd><code>[=TextDirectiveString=]\"-\"</code></dd>\n  <dt><dfn>`TextDirectiveSuffix`</dfn> `::=`</dt>\n  <dd><code>\"-\"[=TextDirectiveString=]</code></dd>\n  <dt><dfn>`TextDirectiveString`</dfn> `::=`</dt>\n  <dd><code>([=TextDirectiveExplicitChar=] | [=PercentEncodedByte=])+</code></dd>\n  <dt><dfn>`TextDirectiveExplicitChar`</dfn> `::=`</dt>\n  <dd>\n  <code>\n    [a-zA-Z0-9] | \"!\" | \"$\" | \"'\" | \"(\" | \")\" | \"*\" | \"+\" | \".\" | \"/\" | \":\" |\n    \";\" | \"=\" | \"?\" | \"@\" | \"_\" | \"~\"\n    </code>\n  <div class = \"note\">\n    A [=TextDirectiveExplicitChar=] is any [=URL code point=] that is not explicitly used in the\n    [=FragmentDirective=] or [=ValidTextDirective=] syntax, that is \"&\", \"-\", and \",\".  If a text\n    fragment refers to a \"&\", \"-\", or \",\" character in the document, it will be percent-encoded in\n    the fragment.\n  </div>\n  </dd>\n  <dt><dfn>`PercentEncodedByte`</dfn> `::=`</dt>\n  <dd><code>\"%\" [a-zA-Z0-9][a-zA-Z0-9]</code></dd>\n</dl>\n\n## Text Directives ## {#text-directives}\n\nA <dfn>text directive</dfn> is a kind of [=/directive=] representing a range of\ntext to be indicated to the user. It is a <a spec=infra>struct</a> that consists of\nfour strings: <dfn for=\"text directive\">start</dfn>,\n<dfn for=\"text directive\">end</dfn>,\n<dfn for=\"text directive\">prefix</dfn>, and\n<dfn for=\"text directive\">suffix</dfn>. [=text directive/start=]\nis required to be non-null. The other three items may be set to null,\nindicating they weren't provided. The empty string is not a valid value for any\nof these items.\n\nSee [[#syntax]] for the what each of these components means and how they're\nused.\n\n<div algorithm=\"percent-decode a text directive term\">\n  To <dfn>percent-decode a text directive term</dfn> given an input <a spec=infra>string</a> |term|:\n\n  <ol class=\"algorithm\">\n    1. If |term| is null, return null.\n    1. <a spec=infra>Assert</a>: |term| is an <a spec=infra>ASCII string</a>.\n    1. Let |decoded bytes| be the result of <a spec=url for=string\n        lt=\"percent-decode\">percent-decoding</a> |term|.\n    1. Return the result of running <a spec=encoding>UTF-8 decode without BOM</a> on |decoded\n        bytes|.\n  </ol>\n</div>\n\n<div algorithm=\"parse a text directive\">\n  To <dfn>parse a text directive</dfn>, on an <a spec=\"infra\">string</a> |text\n  directive value|, run these steps:\n\n  <div class=\"note\">\n    <p>\n      This algorithm takes a single text directive value string as input (e.g.  \"prefix-,foo,bar\") and\n      attempts to parse the string into the components of the directive (e.g. (\"prefix\", \"foo\", \"bar\",\n      null)). See [[#syntax]] for the what each of these components means and how they're used.\n    </p>\n    <p>\n      Returns null if the input is invalid. Otherwise, returns a [=text directive=].\n    </p>\n  </div>\n\n  <ol class=\"algorithm\">\n    1. Let |prefix|, |suffix|, |start|, |end|, each be null.\n    1. <a spec=\"infra\">Assert</a>: |text directive value| is an <a spec=\"infra\">ASCII string</a>\n        with no code points in the <a spec=\"URL\">fragment percent-encode set</a> and no instances of\n        U+0026 (&).\n    1. Let |tokens| be a <a for=/>list</a> of <a spec=\"infra\">strings</a> that result from\n        <a lt=\"strictly split a string\">strictly splitting</a> |text directive value| on U+002C (,).\n    1. If |tokens| has <a for=list>size</a> less than 1 or greater than 4, return null.\n    1. If the first item of |tokens| <a spec=infra for=string>ends with</a> U+002D (-):\n        1. Set |prefix| to the <a spec=infra lt=\"code point substring\">substring</a> of |tokens|[0]\n            from 0 with length |tokens|[0]'s <a spec=infra for=string lt=\"code point\n            length\">length</a> - 1.\n        1. Remove the first item of |tokens|.\n        1. If |prefix| is the empty string or contains any instances of U+002D (-), return null.\n        1. If |tokens| is <a spec=\"infra\" for=\"list\">empty</a>, return null.\n    1. If the last item of |tokens| <a spec=infra for=string>starts with</a> U+002D (-):\n        1. Set |suffix| to the <a spec=infra lt=\"code point substring to the end of the\n            string\">substring</a> of the last item of |tokens| from 1 to the end of the string.\n        1. Remove the last item of |tokens|.\n        1. If |suffix| is the empty string or contains any instances of U+002D (-), return null.\n        1. If |tokens| is <a spec=\"infra\" for=\"list\">empty</a>, return null.\n    1. If |tokens| has <a spec=infra for=list>size</a> greater than 2, return null.\n    1. <a spec=infra>Assert</a>: |tokens| has <a spec=infra for=list>size</a> 1 or 2.\n    1. Set |start| to the first item in |tokens|.\n    1. Remove the first item in |tokens|.\n    1. If |start| is the empty string or contains any instances of U+002D (-), return null.\n    1. If |tokens| is not <a spec=infra for=list>empty</a>:\n        1. Set |end| to the first item in |tokens|.\n        1. If |end| is the empty string or contains any instances of U+002D (-), return null.\n    1. Return a new [=text directive=], with\n        <dl class=\"props\">\n          <dt>[=text directive/prefix=]</dt>\n          <dd>The [=percent-decode a text directive term|percent-decoding=] of |prefix|</dd>\n          <dt>[=text directive/start=]</dt>\n          <dd>The [=percent-decode a text directive term|percent-decoding=] of |start|</dd>\n          <dt>[=text directive/end=]</dt>\n          <dd>The [=percent-decode a text directive term|percent-decoding=] of |end|</dd>\n          <dt>[=text directive/suffix=]</dt>\n          <dd>The [=percent-decode a text directive term|percent-decoding=] of |suffix|</dd>\n        </dl>\n  </ol>\n</div>\n\n<div algorithm=\"parse the fragment directive\">\n\nTo <dfn>parse the fragment directive</dfn>, an an <a spec=\"infra\">ASCII string</a> |fragment\ndirective|, run these steps:\n\n<div class=\"note\">\n  This algorithm takes the fragment directive string (i.e. the part that follows \":~:\") and returns\n  a list of [=text directive=] objects parsed from that string. Can return an empty list.\n</div>\n\n<ol class=\"algorithm\">\n  1. Let |directives| be the result of <a spec=\"infra\" lt=\"strictly split a string\">strictly\n      splitting</a> |fragment directive| on U+0026 (&).\n  1. Let |output| be an initially empty <a spec=\"infra\">list</a> of [=text directives=].\n  1. <a spec=\"infra\" for=\"list\">For each</a> <a spec=\"infra\">string</a> |directive| in |directives|:\n      1. If |directive| does not <a spec=\"infra\" lt=\"starts with\" for=\"string\">start with</a>\n          \"<code>text=</code>\", then <a spec=\"infra\" for=\"iteration\">continue</a>.\n      1. Let |text directive value| be the <a spec=\"infra\" lt=\"code point substring to the end of\n          the string\">code point substring</a> from 5 to the end of |directive|.\n          <div class=\"note\">Note: this may be the empty string.</div>\n      1. Let |parsed text directive| be the result of [=parse a text directive|parsing=] |text\n          directive value|.\n      1. If |parsed text directive| is non-null, <a spec=\"infra\" for=\"list\">append</a> it to\n          |output|.\n  1. Return |output|.\n\n</ol>\n\n</div>\n\n### Invoking Text Directives ### {#invoking-text-directives}\n\nThis section describes how text directives in a document's [=Document/pending text directives=] are\nprocessed and invoked to cause indication of the relevant text passages.\n\n<div class=\"note\">\n    The summarized changes in this section:\n\n    * Modify the indicated part processing model to try processing [=Document/pending text directives=]\n        into a [=range=] that will be returned as the indicated part.\n    * Modify \"scrolling to a fragment\" to correctly scroll and set the Document's target element in the case\n        of a [=range=] based indicated part.\n    * Ensure [=Document/pending text directives=] is reset to null when the user agent has finished the\n        fragment search for the current navigation/traversal.\n    * If the user agent finishes searching for a text directive, ensure it tries the regular\n        fragment as a fallback.\n</div>\n\nIn <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#the-indicated-part-of-the-document\">\nindicated part</a>, enable a fragment to indicate a [=range=]. Make the following changes:\n\n>   <strong>Monkeypatching [[HTML#scrolling-to-a-fragment]]:</strong>\n>\n>   <div class=\"monkeypatch\">\n>   For an HTML document |document|, the following processing model must be followed to determine\n>   its indicated part:\n>\n>   1. <span class=\"diff\">Let |text directives| be the document's [=Document/pending text directives=].\n>       </span>\n>   1. <span class=\"diff\">If |text directives| is non-null then:</span>\n>       1. <span class=\"diff\">Let |ranges| be a <a spec=infra>list</a> that is the result of running\n>           the [=invoke text directives=] steps with |text directives| and the document.</span>\n>       1. <span class=\"diff\">If |ranges| is non-empty, then:</span>\n>           1. <span class=\"diff\">Let |firstRange| be the first item of |ranges|.</span>\n>           1. <span class=\"diff\">Visually indicate each [=range=] in |ranges| in an\n>               [=implementation-defined=] way. The indication must not be observable from author\n>               script. See [[#indicating-the-text-match]].</span>\n>               <div class=\"note\">\n>                 The first [=range=] in |ranges| is the one that gets scrolled into view but all\n>                 ranges should be visually indicated to the user.\n>               </div>\n>           1. <span class=\"diff\">Set |firstRange| as |document|'s indicated part, return.</span>\n>   1. Let fragment be document's URL's fragment.\n>   1. If fragment is the empty string, then return the special value top of the document.\n>   1. Let potentialIndicatedElement be the result of finding a potential indicated element given\n>       document and fragment.\n>   1. ...\n>\n>   </div>\n\nIn <a spec=HTML>scroll to the fragment</a>, handle an indicated part that is a [=range=] and also\nprevent fragment scrolling if the force-load-at-top policy is enabled. Make the following changes:\n\n>   <strong>Monkeypatching [[HTML#scrolling-to-a-fragment]]:</strong>\n>\n>   <div class=\"monkeypatch\">\n>   1. If document's indicated part is null, then set document's target element to null.\n>   2. Otherwise, if document's indicated part is top of the document, then:\n>       1. Set document's target element to null.\n>       2. Scroll to the beginning of the document for document.\n>       3. Return.\n>   3. Otherwise:\n>       1. Assert: document's indicated part is an element <span class=\"diff\">or it is a [=range=].</span>\n>       2. <span class=\"diff\">Let |scrollTarget| be |document|'s indicated part.</span>\n>       3. <span class=\"diff\">Let |target| be |scrollTarget|.</span>\n>       4. <span class=\"diff\">If |target| is a [=range=], then:</span>\n>           1. <span class=\"diff\">Set |target| to be the [=first common ancestor=] of |target|'s\n>               [=range/start node=] and [=range/end node=].</span>\n>           2. <span class=\"diff\">While |target| is non-null and is not an [=element=], set |target| to\n>               |target|'s [=tree/parent=].</span>\n>               <div class=\"issue\">\n>                   What should be set as target if inside a shadow tree?\n>                   <a href=\"https://github.com/WICG/scroll-to-text-fragment/issues/190\">#190</a>\n>               </div>\n>       5. <span class=\"diff\">Assert: |target| is an [=element=].</span>\n>       6. Set |document|'s target element to |target|.\n>       7. Run the ancestor details revealing algorithm on |target|.\n>       8. Run the ancestor hidden-until-found revealing algorithm on |target|.\n>           <div class=\"issue\">\n>               These revealing algorithms currently wont work well since |target| could be an\n>               ancestor or even the root document node. Issue\n>               <a href=\"https://github.com/WICG/scroll-to-text-fragment/issues/89\">#89</a> proposes\n>               restricting matches to `contain:style layout` blocks which would resolve this\n>               problem.\n>           </div>\n>       9. <span class=\"diff\">Let |blockPosition| be \"center\" if |scrollTarget| is a [=range=],\n>           \"start\" otherwise.</span>\n>           <div class=\"note\">\n>             Scrolling to a text directive centers it in the block flow direction.\n>           </div>\n>       10. <strike class=\"diff\">Scroll |target| into view, with behavior set to \"auto\", block set to\n>           \"start\", and inline set to \"nearest\".</strike>\n>\n>           <li value=\"10\"><span class=\"diff\">[=scroll a target into view=],\n>           with <em>target</em> set to |scrollTarget|, <em>behavior</em> set to \"auto\",\n>           <em>block</em> set to |blockPosition|, and <em>inline</em> set to \"nearest\".</span>\n>\n>           <span class=\"diff\">Implementations MAY avoid scrolling to the target if it is\n>           produced from a [=text directive=].</span></li>\n>       11. Run the focusing steps for target, with the Document's viewport as the fallback target.\n>           <div class=\"issue\">Implementation note: Blink doesn’t currently set focus for text\n>           fragments, it probably should? TODO: file crbug.</div>\n>       12. Move the sequential focus navigation starting point to target.\n>\n>   </div>\n\nThe next two monkeypatches ensure the user agent clears [=Document/pending text directives=] when\nthe fragment search is complete. In the case where a text directive search finishes because parsing\nhas stopped, it tries one more search for a non-text directive fragment.\n\nIn the definition of <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#try-to-scroll-to-the-fragment\">\ntry to scroll to the fragment</a>:\n\n>   <strong>Monkeypatching [[HTML#scrolling-to-a-fragment]]:</strong>\n>\n>   <div class=\"monkeypatch\">\n>   To try to scroll to the fragment for a Document |document|, perform the following steps in\n>   parallel:\n>   1. Wait for an implementation-defined amount of time. (This is intended to allow the user agent\n>       to optimize the user experience in the face of performance concerns.)\n>   2. Queue a global task on the navigation and traversal task source given document's relevant\n>       global object to run these steps:\n>       1. <strike class=\"diff\">If document has no parser, or its parser has stopped parsing, or the user agent\n>           has reason to believe the user is no longer interested in scrolling to the fragment, then\n>           abort these steps.</strike>\n>           <li value=\"1\" class=\"diff\">If the user agent has reason to believe the user is no longer interested in scrolling to\n>           the fragment, then:</span>\n>           1. <span class=\"diff\">Set [=Document/pending text directives=] to null.</span>\n>           1. <span class=\"diff\">Abort these steps.</span>\n>       1. <span class=\"diff\">If the document has no parser, or its parser has stopped parsing,\n>           then:</li>\n>           1. <span class=\"diff\">If [=Document/pending text directives=] is not null, then:</span>\n>               1. <span class=\"diff\">Set [=Document/pending text directives=] to null.</span>\n>               1. <span class=\"diff\"><a spec=HTML>Scroll to the fragment</a> given |document|.</span>\n>           1. <span class=\"diff\">Abort these steps.</span>\n>       2. Scroll to the fragment given document.\n>       3. If document's indicated part is still null, then try to scroll to the fragment for\n>           document. <span class=\"diff\">Otherwise, set [=Document/pending text directives=] to\n>           null.</span>\n\nIn the definition of\n<a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate-fragid\">\nnavigate to a fragment</a>:\n\n>   <strong>Monkeypatching [[HTML#scroll-to-fragid]]:</strong>\n>\n>   <div class=\"monkeypatch\">To navigate to a fragment given navigable |navigable|, ...:\n>     1. ...\n>         <li value=\"8\">Update document for history step application given navigable's active\n>         document, historyEntry, true, scriptHistoryIndex, and scriptHistoryLength. </li>\n>     9. Scroll to the fragment given navigable's active document.\n>         <li class=\"diff\">Set |navigable|'s active document's [=Document/pending text directives=] to\n>         null.</li>\n>     11. Let traversable be navigable's traversable navigable.\n>     12. ...\n\nScrolling to the indicated part is only one of several things that happens from \"scroll to the\nfragment\". Rename it and related definitions:\n\n>   <strong>Monkeypatching [[HTML#scroll-to-fragid]]:</strong>\n>\n>   Rename [[HTML#scroll-to-fragid]] and related steps to \"indicating a fragment\" to reflect its\n>   broader effects.\n\n## Security and Privacy ## {#security-and-privacy}\n\n### Motivation ### {#motivation}\n\n<div class=\"note\">This section is non-normative</div>\n\nCare must be taken when implementing [=text directive=] so that it\ncannot be used to exfiltrate information across origins. Scripts can navigate a\npage to a cross-origin URL with a [=text directive=]. If a malicious\nactor can determine that the text fragment was successfully found in victim\npage as a result of such a navigation, they can infer the existence of any text\non the page.\n\nThe processing model in the following subsections restricts the feature to\nmitigate the expected attack vectors. In summary, text directives are restricted\nto:\n\n* top level navigables (i.e. no iframes).\n    * ISSUE(WICG/scroll-to-text-fragment#240): This isn't strictly true, Chrome\n        allows this for same-origin initiators. Need to update the spec on this\n        point.\n* navigations that are the result of a user action\n* in cases where the navigation has a cross-origin initiator, the destination\n    must be opener isolated (i.e. no references to its global objects in other\n    documents)\n\n\n### Scroll On Navigation ### {#scroll-on-navigation}\n\nA UA may choose to automatically scroll a matched text passage into view. This\ncan be a convenient experience for the user but does present some risks that\nimplementing UAs need to be aware of.\n\nThere are known (and potentially unknown) ways a scroll on navigation might be\ndetectable and distinguished from natural user scrolls.\n\n<div class=\"example\">\n  An origin embedded in an iframe in the target page registers an\n  IntersectionObserver and determines in the first 500ms of page load whether\n  a scroll has occurred. This scroll can be indicative of whether the text\n  fragment was successfully found on the page.\n</div>\n\n<div class=\"example\">\n  Two users share the same network on which traffic is visible between them.\n  A malicious user sends the victim a link with a text fragment to a\n  page. The searched-for text appears nearby to a resource located on a unique\n  (on the page) domain. The attacker may be able to infer the success or failure\n  of the fragment search based on the order of requests for DNS lookup.\n</div>\n\n<div class=\"example\">\n  An attacker sends a link to a victim, sending them to a page that displays\n  a private token. The attacker asks the victim to read back the token. Using\n  a text fragment, the attacker gets the page to load for the victim such that\n  warnings about keeping the token secret are scrolled out of view.\n</div>\n\nAll known cases like this rely on specific circumstances about the target page\nso don't apply generally. With additional restrictions about when the text\nfragment can invoke an attacker is further restricted. Nonetheless, different\nUAs can come to different conclusions about whether these risks are acceptable.\nUAs need to consider these factors when determining whether to scroll as part of\nnavigating to a text fragment.\n\nConforming UAs may choose not to scroll automatically on navigation. Such UAs\nmay, instead, provide UI to initiate the scroll (\"click to scroll\") or none\nat all. In these cases UA should provide some indication to the user that an\nindicated passage exists further down on the page.\n\nThe examples above illustrate that in specific circumstances, it can be\npossible for an attacker to extract 1 bit of information about content on the\npage. However, care must be taken so that such opportunities cannot be\nexploited to extract arbitrary content from the page by repeating the attack.\nFor this reason, restrictions based on user activation and browsing context\nisolation are very important and must be implemented.\n\n<div class=\"note\">\n  Browsing context isolation ensures that no other document can script the\n  target document which helps reduce the attack surface.\n\n  However, it also ensures any malicious use is difficult to hide. A browsing\n  context that's the only one in a group will be a top level browsing context\n  (i.e. a full tab/window).\n</div>\n\nIf a UA does choose to scroll automatically, it must ensure no scrolling is\nperformed while the document is in the background (for example, in an inactive\ntab). This ensures any malicious usage is visible to the user and prevents\nattackers from trying to secretly automate a search in background documents.\n\nIf a UA chooses not to scroll automatically, it must scroll a fallback\nelement-id into view, if provided, regardless of whether a text fragment was\nmatched. Not doing so would allow detecting the text fragment match based on\nwhether the element-id was scrolled.\n\n### Search Timing ### {#search-timing}\n\nA naive implementation of the text search algorithm could allow information\nexfiltration based on runtime duration differences between a matching and non-\nmatching query. If an attacker could find a way to synchronously navigate\nto a [=text directive=]-invoking URL, they would be able to determine\nthe existence of a text snippet by measuring how long the navigation call takes.\n\n<div class=\"note\">\n  The restrictions in [[#restricting-the-text-fragment]] prevent this\n  specific case; in particular, the no-same-document-navigation restriction.\n  However, these restrictions are provided as multiple layers of defence.\n</div>\n\nFor this reason, the implementation <em>must ensure the runtime of\n[[#navigating-to-text-fragment]] steps does not differ based on whether a match\nhas been successfully found</em>.\n\nThis specification does not specify exactly how a UA achieves this as there are\nmultiple solutions with differing tradeoffs. For example, a UA <em>may</em>\ncontinue to walk the tree even after a match is found in [=find a range from a\ntext directive=].  Alternatively, it <em>may</em> schedule an asynchronous task\nto find and set the [=/Document=]'s indicated part.\n\n### Restricting the Text Fragment ### {#restricting-the-text-fragment}\n\n<div class=\"note\">\n  This section integrates with HTML navigation to restrict when an indicated text directive will\n  be allowed to scroll. In summary:\n\n  * Add a boolean <code>text directive user activation</code> to both Document and Request. This\n      flag is set on a document when created from a user activated navigation and consumed if a text\n      directive is scrolled. If unconsumed, it can be transfered to an outgoing navigation request.\n      This implements the user-activation-through-redirects behavior described in the note below.\n  * Define a series of checks, performed on a document and the user involvement and initiator origin\n      state of a navigation, to determine whether a text directive should be allowed to perform a\n      scroll.\n  * Compute the scroll permission from \"finalize a cross document navigation\" and from \"navigate to\n      a fragment steps\" and plumb it through to the \"scroll to the fragment\" steps where its used to\n      abort a text directive scroll.\n\n</div>\n\nAmend the definition of a [=/request=] and of a [=/Document=] to include a new\nboolean [=document/text directive user activation=] field:\n\n>   <strong>Monkeypatching [[FETCH]]:</strong>\n>\n>   A [=/request=] has an associated boolean <dfn for=\"request\">text directive user activation</dfn>,\n>   initially false.\n\n>   <strong>Monkeypatching [[HTML]]:</strong>\n>\n>   Each [=/Document=] has a <dfn for=\"document\">text directive user activation</dfn>, which is a boolean,\n>   initially false.\n>\n>   <div class=\"note\">\n>     [=document/text directive user activation=] provides the necessary user gesture signal to allow\n>     a single activation of a text fragment. It is set to true during document loading only if the\n>     navigation occurred as a result of a user activation and is propagated across client-side\n>     redirects.\n>\n>     If a [=/Document=]'s [=document/text directive user activation=] isn't used to activate a text\n>     fragment, it is instead used to set a new navigation [=/request=]'s [=request/text directive user activation=]\n>     to true. In this way, a [=document/text directive user activation=] can be propagated\n>     from one [=/Document=] to another across a navigation.\n>\n>     Both [=/Document=]'s [=document/text directive user activation=] and [=/request=]'s\n>     [=request/text directive user activation=] are always set to false when used, such that a\n>     single user activation cannot be reused to activate more than one text fragment.\n>   </div>\n\n<div class=\"note\">\n  <p>\n    This mechanism allows text fragments to activate through a common redirect\n    technique used by many popular web sites. Such sites redirect users to\n    their intended destination by responding with a 200 status code containing\n    script to set the <tt>window.location</tt>.\n  </p>\n\n  <p>\n    Unlike real HTTP (<tt>status 3xx</tt>) redirects, these \"client-side\"\n    redirects cannot propagate the fact that the navigation is the result of a\n    user gesture. The [=document/text directive user activation=] mechanism allows passing\n    through this specifically scoped user-activation through such navigations.\n    This means a page is able to programmatically navigate to a text fragment, a\n    single time, as if it has a user gesture. However, since this resets <code>text fragment user\n    activation</code>, further text fragment navigations will not activation without a new user gesture.\n  </p>\n  <p>\n    The following diagram demonstrates how the flag is used to activate a text\n    fragment through a client-side redirect service:\n  </p>\n\n  <img style=\"margin-left:auto;margin-right:auto;display:block\" width=\"745\" height=\"671\" src=\"https://raw.githubusercontent.com/WICG/scroll-to-text-fragment/master/text_fragment_activation_flag.png\" alt=\"Diagram showing how a text fragment flag is set and used\">\n\n  <p>\n    See [redirects.md](redirects.md) for a more in-depth discussion.\n  </p>\n</div>\n\nAmend the <a spec=HTML>create navigation params by fetching</a> steps to transfer the [=active\ndocument=]'s [=document/text directive user activation=] value into <var ignore>request</var>'s\n[=request/text directive user activation=].\n\n> <strong>Monkeypatching [[HTML]]:</strong>\n>\n> <div class=\"monkeypatch\">\n>   1. Assert: this is running in parallel.\n>   2. Let documentResource be entry's document state's resource.\n>   3. Let <var ignore>request</var> be a new request, with\n>\n>      <dl class=\"props\">\n>       <dt>url</dt>\n>       <dd><var ignore>entry</var>'s URL</dd>\n>\n>       <dt>...</dt>\n>       <dd>...</dd>\n>\n>       <dt>referrer policy</dt>\n>       <dd><var ignore>entry</var>'s document state's request referrer policy</dd>\n>\n>       <dt><span class=\"diff\">[=request/text directive user activation=]</span></dt>\n>       <dd><span class=\"diff\">|navigable|'s [=navigable/active document=]'s [=document/text directive user activation=]</span></dd>\n>      </dl>\n>     </li>\n>   4. <span class=\"diff\">Set |navigable|'s [=navigable/active document=]'s [=document/text directive\n>       user activation=] to false.</span>\n>   5. If documentResource is a POST resource, then:\n>       1. ...\n>\n> </div>\n\nAmend the definition of <a spec=HTML>navigation params</a> to include a new field:\n\n>   <strong>Monkeypatching [[HTML]]:</strong>\n>\n>  <dl>\n>   <dt><dfn for=\"navigation params\">user involvement</dfn></dt>\n>   <dd>A <a spec=HTML>user navigation involvement</a> value.</dd>\n>  </dl>\n>\n\nInitialize the [=navigation params/user involvement=] value everywhere a navigation params is\ncreated. Specifically: initialize it to true in the <a spec=HTML>create navigation params by\nfetching</a> case:\n\n> <strong>Monkeypatching [[HTML]]:</strong>\n>\n> <div class=\"monkeypatch\">\n>   To create navigation params by fetching given a session history entry entry, a navigable\n>   navigable, a source snapshot params sourceSnapshotParams, a target snapshot params\n>   targetSnapshotParams, a string cspNavigationType, a navigation ID-or-null navigationId, a\n>   NavigationTimingType navTimingType, <span class=\"diff\">and a <a spec=HTML>user navigation\n>   involvement</a> |user involvement|</span>, perform the following steps. They return a navigation params,\n>   a non-fetch scheme navigation params, or null.\n>\n>   1. Assert: this is running in parallel.\n>   2. ...\n>       <li value=\"23\">Let resultPolicyContainer be the result of determining navigation params policy container given\n>       response's URL, entry's document state's history policy container, sourceSnapshotParams's source\n>       policy container, null, and responsePolicyContainer.</li>\n>   24. If navigable's container is an iframe, and response's timing allow passed flag is set, then\n>       set container's pending resource-timing start time to null.\n>   25. Return a new navigation params, with\n>\n>       <dl>\n>        <dt>id</dt>\n>        <dd>navigationId</dd>\n>        <dt>...</dt>\n>        <dd>...</dd>\n>        <dt>about base URL</dt>\n>        <dd>entry's document state's about base URL</dd>\n>        <dt class=\"diff\">[=navigation params/user involvement=]</dt>\n>        <dd class=\"diff\">|user involvement|</dd>\n>       </dl>\n>\n> </div>\n\nAmend the\n<a href=\"https://html.spec.whatwg.org/multipage/document-lifecycle.html#initialise-the-document-object\">\ncreate and initialize a Document object</a> steps to compute and store the [=document/text directive\nuser activation=] flag:\n\n> <strong>Monkeypatching [[HTML]]:</strong>\n>\n> <div class=\"monkeypatch\">\n>   18. Process link headers given document, navigationParams's response, and \"pre-media\".\n>   19. <div class=\"diff\">Set |document|'s [=document/text directive user activation=] to true if any of the following\n>     conditions hold, false otherwise:\n>       * |navigationParams|'s [=user involvement=] is \"<code>activation</code>\";\n>       * |navigationParams|'s [=user involvement=] is \"<code>browser UI</code>\"; or\n>       * |navigationParams|'s\n>         <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigation-params-request\">request</a>'s\n>         [=request/text directive user activation=] is true.\n>         <div class=\"note\">\n>           It's important that [=document/text directive user activation=] not be copyable so that\n>           only one text fragment can be activated per user-activated navigation.\n>         </div></div>\n>   20. Return |document|.\n>\n> </div>\n\nA <dfn>text directive allowing MIME type</dfn> is a [=MIME type=] whose [=MIME type/essence=] is\n\"<code>text/html</code>\" or \"<code>text/plain</code>\".\n\nNote: As noted in <a\nhref=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#scrolling-to-a-fragment\">scrolling\nto a fragment, fragment processing is defined individually by each MIME type. As such, the\n<a spec=HTML>scroll to the fragment</a> steps where text directives are scrolled should only apply\nto text/html media types. However, in practice, web browsers tend to apply HTML fragment processing\nto other types, such as text/plain (e.g. add an element with an id to a text/plain document,\nnavigating to the fragment-id causes scrolling). While this is the case, enabling text directives in\ntext/plain documents is useful. Other types are explicitly disallowed to prevent the possibility of\nXS-Search attacks on potentially sensitive application data (e.g. text/css, application/json,\napplication/javascript, etc.).\n\nIssue: Is this valid to say in the HTML spec?\n\n<div algorithm=\"check if a text directive can be scrolled\">\n  To <dfn>check if a text directive can be scrolled</dfn>; given a [=/Document=] |document|, an\n  [=/origin=]-or-null |initiator origin|, and <a spec=HTML>user navigation involvement</a>-or-null\n  |user involvement|, follow these steps:\n\n  <ol class=\"algorithm\">\n    1. If |document|'s [=Document/pending text directives=] field is null or empty, return false.\n    1. Let |is user involved| be true if: |document|'s [=document/text directive user activation=] is\n        true, or |user involvement| is one of \"<code>activation</code>\" or \"<code>browser\n        UI</code>\"; false otherwise.\n    1. Set |document|'s [=document/text directive user activation=] to false.\n    1. If |document|'s [=Document/content type=] is not a [=text directive allowing MIME type=],\n        return false.\n    1. If |user involvement| is \"<code>browser UI</code>\", return true.\n        <div class=\"note\">\n          <p>\n            If a navigation originates from browser UI, it's always ok to allow it since it'll be\n            user triggered and the page/script isn't providing the text snippet.\n          </p>\n          <p>\n            Note: The intent in this item is to distinguish cases where the app/page is able to\n            control the URL from those that are fully under the user's control. In the former we\n            want to prevent scrolling of the text fragment unless the destination is loaded in a\n            separate browsing context group (so that the source cannot both control the text snippet\n            and observe side-effects in the navigation). There are some cases where \"browser UI\" may\n            be a grey area in this regard. E.g. an \"open in new window\" context menu item when right\n            clicking on a link.\n          </p>\n          <p>\n            See\n            <a href=\"https://w3c.github.io/webappsec-fetch-metadata/#directly-user-initiated\">\n            sec-fetch-site</a> in [[FETCH-METADATA]] for a related discussion of how this applies.\n          </p>\n        </div>\n    1. If |is user involved| is false, return false.\n    1. If |document|'s [=node navigable=] has a [=navigable/parent=], return false.\n    1. If |initiator origin| is non-null and |document|'s [=Document/origin=] is [=same origin=]\n        with |initiator origin|, return true.\n    1. If |document|'s [=Document/browsing context=]'s [=browsing context/group=]'s\n        <a spec=HTML>browsing context set</a> has length 1, return true.\n        <div class=\"note\">\n          i.e. Only allow navigation from a cross-origin element/script if the\n          document is loaded in a noopener context. That is, a new top level\n          browsing context group to which the navigator does not have script access\n          and which can be placed into a separate process.\n        </div>\n    1. Otherwise, return false.\n  </ol>\n</div>\n\nAmend (the already amended, in [[#invoking-text-directives]]) <a spec=HTML>scroll to the\nfragment</a> steps to add a new parameter, a boolean |allow text directive scroll|:\n\n> <strong>Monkeypatching [[HTML#scrolling-to-a-fragment]]:</strong>\n>\n> <div class=\"monkeypatch\">\n>   To scroll to the fragment given a Document |document| <span class=\"diff\">and boolean |allow text\n>   directive scroll|</span>:\n>\n>   1. If document's indicated part is null, then set document's target element to null.\n>   2. ...\n>   3. Otherwise:\n>       1. Assert: document's indicated part is an element or it is a [=range=].\n>       2. ...\n>           <li value=\"4\">If |target| is a [=range=], then:</li>\n>           1. <span class=\"diff\">If |allow text directive scroll| is false, return.</span>\n>           1. Set |target| to be the [=first common ancestor=] of |target|'s [=range/start node=]\n>               and [=range/end node=].\n>           1. ...\n>\n> </div>\n\nAmend the <a spec=HTML>try to scroll to the fragment</a> by adding a boolean flag |allow text\ndirective scroll| and replacing the steps of the task queued in step 2:\n\n> <strong>Monkeypatching [[HTML]]:</strong>\n>\n> <div class=\"monkeypatch\">\n>  To try to scroll to the fragment for a Document |document|, <span class=\"diff\">with boolean\n>  |allow text directive scroll|</span>, perform the following steps in parallel:\n>\n>   1. Wait for an implementation-defined amount of time. (This is intended to allow the user agent\n>       to optimize the user experience in the face of performance concerns.)\n>   2. Queue a global task on the navigation and traversal task source given document's relevant\n>       global object to run these steps:\n>       1. If document has no parser, or its parser has stopped parsing, or the user\n>           agent has reason to believe the user is no longer interested in scrolling to\n>           the fragment, then abort these steps.\n>       2. Scroll to the fragment given |document| <span class=\"diff\">and |allow text directive\n>           scroll|.</span>\n>       3. If document's indicated part is still null, then try to scroll to the fragment for\n>           |document|<span class=\"diff\"> and |allow text directive scroll|</span>.\n>\n>   </div>\n\nAmend the <a spec=HTML>update document for history step application</a> steps to take a boolean\n|allow text directive scroll| and use it when scrolling to a fragment:\n\n> <strong>Monkeypatching [[HTML]]:</strong>\n>\n> <div class=\"monkeypatch\">\n>   To update document for history step application given a Document document, a session history\n>   entry entry, a boolean doNotReactivate, integers scriptHistoryLength and scriptHistoryIndex,\n>   an optional list of session history entries entriesForNavigationAPI, <span class=\"diff\">and a\n>   boolean |allow text directive scroll|</span>:\n>\n>   1. Let documentIsNew be true if |document|'s latest entry is null; otherwise false.\n>   1. ...\n>       <li value=\"5\">If documentsEntryChanged is true, then:\n>       1. Let oldURL be document's latest entry's URL.\n>       2. ...\n>   6. If documentIsNew is true, then:\n>       1. Try to scroll to the fragment with |document| <span class=\"diff\">and |allow text\n>           directive scroll|.</span>\n>\n> </div>\n\nAmend the <a spec=HTML>apply the history step</a> algorithm to take a boolean |allow text directive\nscroll| and pass it through when calling <a spec=HTML>update document for history step application\n</a>:\n\n> <strong>Monkeypatching [[HTML]]:</strong>\n>\n> <div class=\"monkeypatch\">\n>\n> To apply the history step given a non-negative integer step to a traversable navigable\n> traversable, with boolean checkForCancelation, source snapshot params-or-null\n> sourceSnapshotParams, navigable-or-null initiatorToCheck, user navigation involvement-or-null\n> userInvolvementForNavigateEvents, <span class=\"diff\">and boolean |allow text directive scroll|\n> (default false)</span> perform the following steps. They\n> return \"initiator-disallowed\", \"canceled-by-beforeunload\", \"canceled-by-navigate\", or \"applied\".\n>\n> 14. While completedChangeJobs does not equal totalChangeJobs:\n>     1. ...\n>         <li value=\"11\">Queue a global task on the navigation and traversal task source given\n>         navigable's active window to run the steps:\n>             1. If changingNavigableContinuation's update-only is false, then:\n>                 1. ...\n>                 2. Activate history entry |targetEntry| for navigable.\n>             2. Let updateDocument be an algorithm step which performs update document for history\n>                 step application given |targetEntry|'s document, |targetEntry|,\n>                 changingNavigableContinuation's update-only, scriptHistoryLength,\n>                 scriptHistoryIndex, entriesForNavigationAPI, <span class=\"diff\">and |allow text\n>                 directive scroll|</span>\n>             3. If |targetEntry|'s document is equal to displayedDocument, then perform\n>                 updateDocument.\n> 15. Let totalNonchangingJobs be the size of nonchangingNavigablesThatStillNeedUpdates.\n>\n> </div>\n\nAmend the <a spec=HTML>apply the push/replace history step</a> to take and pass |allow text\ndirective scrolling| to apply the history step:\n\n> <strong>Monkeypatching [[HTML]]:</strong>\n>\n> <div class=\"monkeypatch\">\n>  To apply the push/replace history step given a non-negative integer |step| to a traversable\n>  navigable |traversable|, <span class=\"diff\">with boolean |allow text directive scroll| (default\n>  false)</span>:\n>\n>  Return the result of applying the history step |step| to |traversable| given false, null, null,\n>  null, <span class=\"diff\">|allow text directive scroll|</span>.\n> </div>\n\nNote: The |allow text directive scroll| is intentionally not set for traversal and reload cases.\nThis avoids extensive plumbing and checks for initiator origin and user involvement and history\nscroll state should take precedence anyway. The text directive may still be used as the indicated\npart of the document so highlights will be restored.\n\nAmend the <a spec=HTML>finalize a cross-document navigation</a> to take a |user involvement|\nparameter and compute and pass |allow text directive scrolling| to apply the push/replace history\nstep:\n\n> <strong>Monkeypatching [[HTML]]:</strong>\n>\n> <div class=\"monkeypatch\">\n>\n> To finalize a cross-document navigation given a navigable navigable, history handling behavior\n> historyHandling, session history entry historyEntry, <span class=\"diff\"> and <a spec=HTML>user\n> navigation involvement</a> |user involvement| (default \"none\")</span>:\n>\n> 1. Assert: this is running on navigable's traversable navigable's session history traversal queue.\n> 2. ...\n>     <li value=\"10\"><span class=\"diff\">Let |allow text directive scroll| be the result of [=check if a text\n>     directive can be scrolled|checking if a text directive can be scrolled=], given\n>     |historyEntry|'s [=she/document=], |historyEntry|'s <a spec=HTML>document state</a>'s\n>     [=document state/initiator origin=], and |user involvement|</span>\n> 11. Apply the push/replace history step targetStep to traversable, <span class=\"diff\">with |allow\n>     text directive scroll|.</span>\n\nAmend the <a spec=HTML>navigate</a> algorithm to pass |user involvement| to the finalize a\ncross-document navigation steps:\n\n> <strong>Monkeypatching [[HTML]]:</strong>\n>\n> <div class=\"monkeypatch\">\n>\n> 1. ...\n>     <li value=\"20\">. In parallel, run these steps:</li>\n>     1. ...\n>         <li value=\"9\">. Attempt to populate the history entry's document for historyEntry, given\n>         navigable, \"navigate\", sourceSnapshotParams, targetSnapshotParams, navigationId,\n>         navigationParams, cspNavigationType, with allowPOST set to true and completionSteps set to\n>         the following step:</li>\n>         1. Append session history traversal steps to navigable's traversable to finalize a\n>             cross-document navigation given navigable, historyHandling, historyEntry,\n>             <span class=\"diff\">and |userInvolvement|</span>.\n\nAmend the <a spec=HTML>Navigate to a fragment</a> algorithm to take an |initiator origin| parameter\nand pass the |allow text directive scroll| flag when scrolling to the fragment:\n\n> <strong>Monkeypatching [[HTML]]:</strong>\n>\n> <div class=\"monkeypatch\">\n>\n> To navigate to a fragment given a navigable navigable, a URL url, a history handling behavior\n> historyHandling, a user navigation involvement |userInvolvement|, a serialized state-or-null\n> navigationAPIState, navigation ID navigationId, <span class=\"diff\">an [=/origin=] |initiator\n> origin|</span>:\n>\n> 1. Let navigation be |navigable|'s active window's navigation API.\n> 2. ...\n>     <li value=\"14\"> Update document for history step application given navigable's active document, historyEntry, true, scriptHistoryIndex, and scriptHistoryLength.\n> 15. Update the navigation API entries for a same-document navigation given navigation, historyEntry, and historyHandling.\n> 16. <span class=\"diff\">Let |allow text directive scroll| be the result of [=check if a text\n>     directive can be scrolled|checking if a text directive can be scrolled=], given\n>     |navigable|'s [=active document=], |initiator origin|, and |userInvolvement|</span>\n> 17. Scroll to the fragment given |navigable|'s active document<span class=\"diff\">, and |allow text\n>     directive scroll|.</span>\n>\n> </div>\n\nAmend the <a spec=HTML>navigate</a> algorithm to pass the initiator origin when performing a\nfragment navigation:\n\n> <strong>Monkeypatching [[HTML]]:</strong>\n>\n> <div class=\"monkeypatch\">\n>\n> 10. If the navigation must be a replace given url and navigable's active document, then set historyHandling to \"replace\".\n> 11. If all of the following are true:\n>     * documentResource is null;\n>     * response is null;\n>     * url equals navigable's active session history entry's URL with exclude fragments set to true; and\n>     * url's fragment is non-null,\n>\n>     then:\n>\n>     1. Navigate to a fragment given navigable, url, historyHandling, userInvolvement,\n>         navigationAPIState, navigationId, <span class=\"diff\">and <var ignore>\n>         initiatorOriginSnapshot</var></span>\n>     1. Let navigation be |navigable|'s active window's navigation API.\n>\n> </div>\n\n### Restricting Scroll on Load ### {#restricting-scroll-on-load}\n\nThis section defines how the `force-load-at-top` policy is used to prevent all\ntypes of scrolling when loading a new document, including but not limited to\ntext directives.\n\nISSUE(WICG/scroll-to-text-fragment#242): Need to decide how `force-load-at-top`\ninteracts with the Navigation API.\n\nAmend the <a spec=HTML>restore persisted state</a> steps to take a new boolean\nparameter which suppresses scroll restoration:\n\n> <strong>Monkeypatching [[HTML]]:</strong>\n>\n> <div class=\"monkeypatch\">\n>   To restore persisted state from a session history entry <var ignore>entry</var>\n>   <span class=\"diff\">, and boolean |suppressScrolling|</span>:\n>\n>  1. If entry's scroll restoration mode is \"auto\", <span class=\"diff\">|suppressScrolling|\n>     is false,</span> and entry's document's relevant global object's navigation API's suppress\n>     normal scroll restoration during ongoing navigation is false, then restore scroll position\n>     data given entry.\n>  2. ...\n\n\nAmend the <a spec=HTML>update document for history step application</a> steps\nto check the `force-load-at-top` policy and avoid scrolling in a new document\nif it's set.\n\n> <strong>Monkeypatching [[HTML]]:</strong>\n>\n> <div class=\"monkeypatch\">\n>   1. ...\n>       <li value=\"4\">Set document's history object's length to scriptHistoryLength.</li>\n>   5. <span class=\"diff\">Let |scrollingBlockedInNewDocument| be the result of\n>       <a href=\"https://wicg.github.io/document-policy#algo-get-policy-value\">getting the policy\n>       value</a> for `force-load-at-top` for |document|.</span>\n>   5. If documentsEntryChanged is true, then:\n>       1. Let oldURL be document's latest entry's URL.\n>       2. ...\n>           <li value=\"5\"> If documentIsNew is false, then:\n>           1. Update the navigation API entries for a same-document navigation given navigation,\n>               entry, and \"traverse\".\n>           2. Fire an event named popstate...\n>           3. Restore persisted state given entry <span class=\"diff\">and\n>               |suppressScrolling| set to false.</span>\n>           4. If oldURL's fragment is not equal to...\n>       6. Otherwise,\n>           1. Assert: entriesForNavigationAPI is given.\n>           2. Restore persisted state given entry <span class=\"diff\">and\n>               |scrollingBlockedInNewDocument|.</span>\n>           3. Initialize the navigation API entries for a new document given navigation,\n>               entriesForNavigationAPI, and entry.\n>   6. If documentIsNew is true, then:\n>       1. <span class=\"diff\">If |scrollingBlockedInNewDocument| is false,</span> try to scroll to\n>           the fragment for document.\n>       2. At this point scripts may run for the newly-created document document.\n>   7. Otherwise, if documentsEntryChanged is false and doNotReactivate is false, then:\n>       1. ...\n>\n> </div>\n\n## Navigating to a Text Fragment ## {#navigating-to-text-fragment}\n\n<div class=\"note\">\nThe text fragment specification proposes an amendment to\n[[html#scroll-to-fragid]]. In summary, if a [=text directive=] is\npresent and a match is found in the page, the text fragment takes precedent over\nthe element fragment as the indicated part. We amend the HTML Document's\nindicated part processing model to return a [=range=], rather than an\n[=element=], that will be scrolled into view.\n</div>\n\n<div algorithm=\"first common ancestor\">\nTo find the <dfn>first common ancestor</dfn> of two nodes |nodeA| and |nodeB|,\nfollow these steps:\n\n\n  <ol class=\"algorithm\">\n    1. Let |commonAncestor| be |nodeA|.\n    1. While |commonAncestor| is non-null and is not a [=shadow-including inclusive\n        ancestor=] of |nodeB|, let |commonAncestor| be |commonAncestor|’s\n        [=shadow-including parent=].\n    1. Return |commonAncestor|.\n  </ol>\n</div>\n\n<div algorithm=\"shadow-including parent\">\nTo find the <dfn>shadow-including parent</dfn> of |node| follow these steps:\n\n  <ol class=\"algorithm\">\n    1. If |node| is a [=/shadow root=], return |node|'s [=DocumentFragment/host=].\n    1. Otherwise, return |node|'s [=tree/parent=].\n  </ol>\n</div>\n\n### Finding Ranges in a Document ### {#finding-ranges-in-a-document}\n\n<div class=\"note\">\n  This section outlines several algorithms and definitions that specify how to\n  turn a full fragment directive string into a list of [=Ranges=] in the\n  document.\n\n  At a high level, we take a fragment directive string that looks like this:\n  <pre>\n    text=prefix-,foo&unknown&text=bar,baz\n  </pre>\n\n  We break this up into the individual text directives:\n\n  <pre>\n    text=prefix-,foo\n    text=bar,baz\n  </pre>\n\n  For each text directive, we perform a search in the document for the first\n  instance of rendered text that matches the restrictions in the directive.\n  Each search is independent of any others; that is, the result is the same\n  regardless of how many other directives are provided or their match result.\n\n  If a directive successfully matches to text in the document, it returns a\n  [=range=] indicating that match in the document. The\n  [=invoke text directives=] steps are the high level API provided by this\n  section. These return a <a spec=infra>list</a> of [=ranges=] that were matched\n  by the individual directive matching steps, in the order the directives were\n  specified in the fragment directive string.\n\n  If a directive was not matched, it does not add an item to the returned\n  list.\n</div>\n\n<div algorithm=\"invoke text directives\">\n  To <dfn>invoke text directives</dfn>, given as input a <a spec=infra>list</a> of [=text\n  directives=] |text directives| and a [=/Document=] |document|, run these steps:\n\n  <div class=\"note\">\n    This algorithm returns a <a spec=infra>list</a> of [=ranges=] that are to be visually indicated,\n    the first of which will be scrolled into view (if the UA scrolls automatically).\n  </div>\n\n  <ol class=\"algorithm\">\n    1. Let |ranges| be a <a spec=infra>list</a> of [=ranges=], initially empty.\n    1. <a spec=infra for=list>For each</a> [=text directive=] |directive| of |text directives|:\n        1. If the result of running [=find a range from a text directive=] given |directive| and\n            |document| is non-null, then [=list/append=] it to |ranges|.\n    1. Return |ranges|.\n  </ol>\n</div>\n\n<div algorithm=\"find a range from a text directive\">\nTo <dfn>find a range from a text directive</dfn>, given a\n[=text directive=] |parsedValues| and [=/Document=] |document|, run the\nfollowing steps:\n\n<div class=\"note\">\n  This algorithm takes as input a successfully parsed text directive and a\n  document in which to search. It returns a [=range=] that points to the first\n  text passage within the document that matches the searched-for text and\n  satisfies the surrounding context. Returns null if no such passage exists.\n\n  [=text directive/end=] can be null. If omitted, this is an \"exact\"\n  search and the returned [=range=] will contain a string exactly matching\n  [=text directive/start=]. If [=text directive/end=] is\n  provided, this is a \"range\" search; the returned [=range=] will start with\n  [=text directive/start=] and end with\n  [=text directive/end=]. In the normative text below, we'll call a\n  text passage that matches the provided [=text directive/start=] and\n  [=text directive/end=], regardless of which mode we're in, the\n  \"matching text\".\n\n  Either or both of [=text directive/prefix=] and\n  [=text directive/suffix=] can be null, in which case context on that\n  side of a match is not checked. E.g. If [=text directive/prefix=] is\n  null, text is matched without any requirement on what text precedes it.\n</div>\n<div class=\"note\">\n  While the matching text and its prefix/suffix can span across\n  block-boundaries, the individual parameters to these steps cannot. That is,\n  each of [=text directive/prefix=], [=text directive/start=],\n  [=text directive/end=], and [=text directive/suffix=] will only\n  match text within a single block.\n\n  <div class=\"example\">\n    <pre>:~:text=The quick,lazy dog</pre> will fail to match in\n\n    ```\n    <div>The<div> </div>quick brown fox</div>\n    <div>jumped over the lazy dog</div>\n    ```\n\n    because the starting string \"The quick\" does not appear within a single,\n    uninterrupted block. The instance of \"The quick\" in the document has a\n    block element between \"The\" and \"quick\".\n\n    It does, however, match in this example:\n\n    ```\n    <div>The quick brown fox</div>\n    <div>jumped over the lazy dog</div>\n    ```\n\n  </div>\n</div>\n  <ol class=\"algorithm\">\n    1. Let |searchRange| be a [=range=] with [=range/start=] (|document|, 0) and\n        [=range/end=] (|document|, |document|'s [=Node/length=])\n    1. While |searchRange| is not [=range/collapsed=]:\n        1. Let |potentialMatch| be null.\n        1. If |parsedValues|'s [=text directive/prefix=] is not null:\n            1. Let |prefixMatch| be the the result of running the [=find a string\n                in range=] steps with |query| |parsedValues|'s\n                [=text directive/prefix=], |searchRange| |searchRange|,\n                |wordStartBounded| true, |wordEndBounded| false and\n                |matchMustBeAtBeginning| false.\n            1. If |prefixMatch| is null, return null.\n            1. Set |searchRange|'s [=range/start=] to the first [=/boundary point=]\n                [=boundary point/after=] |prefixMatch|'s [=range/start=]\n            1. Let |matchRange| be a [=range=] whose [=range/start=] is\n                |prefixMatch|'s [=range/end=] and [=range/end=] is |searchRange|'s\n                [=range/end=].\n            1. Advance |matchRange|'s [=range/start=] to the\n                [=next non-whitespace position=].\n            1. If |matchRange| is [=range/collapsed=] return null.\n                <div class=\"note\">\n                  This can happen if |prefixMatch|'s [=range/end=] or its subsequent\n                  non-whitespace position is at the end of the document.\n                </div>\n            1. [=/Assert=]: |matchRange|'s [=range/start node=] is a {{Text}} node.\n                <div class=\"note\">\n                  |matchRange|'s [=range/start=] now points to the next\n                  non-whitespace text data following a matched prefix.\n                </div>\n            1. Let |mustEndAtWordBoundary| be true if |parsedValues|'s\n                [=text directive/end=] is non-null or\n                |parsedValues|'s [=text directive/suffix=] is null, false\n                otherwise.\n            1. Set |potentialMatch| to the result of running the [=find a string in\n                range=] steps with |query| |parsedValues|'s\n                [=text directive/start=], |searchRange| |matchRange|,\n                |wordStartBounded| false, |wordEndBounded|\n                |mustEndAtWordBoundary| and |matchMustBeAtBeginning| true.\n            1. If |potentialMatch| is null, [=iteration/continue=].\n                <div class=\"note\">\n                  In this case, we found a prefix but it was followed by something\n                  other than a matching text so we'll continue searching for the\n                  next instance of [=text directive/prefix=].\n                </div>\n        1. Otherwise:\n            1. Let |mustEndAtWordBoundary| be true if |parsedValues|'s\n                [=text directive/end=] is non-null or\n                |parsedValues|'s [=text directive/suffix=] is null, false\n                otherwise.\n            1. Set |potentialMatch| to the result of running the [=find a string in\n                range=] steps with |query| |parsedValues|'s\n                [=text directive/start=], |searchRange| |searchRange|,\n                |wordStartBounded| true, |wordEndBounded|\n                |mustEndAtWordBoundary| and |matchMustBeAtBeginning| false.\n            1. If |potentialMatch| is null, return null.\n            1. Set |searchRange|'s [=range/start=] to the first [=/boundary point=]\n                [=boundary point/after=] |potentialMatch|'s [=range/start=]\n        1. Let |rangeEndSearchRange| be a [=range=] whose [=range/start=] is\n            |potentialMatch|'s [=range/end=] and whose [=range/end=] is\n            |searchRange|'s [=range/end=].\n        1. While |rangeEndSearchRange| is not [=range/collapsed=]:\n            1. If |parsedValues|'s [=text directive/end=] item is\n                non-null, then:\n                1. Let |mustEndAtWordBoundary| be true if |parsedValues|'s\n                    [=text directive/suffix=] is null, false otherwise.\n                1. Let |endMatch| be the result of running the [=find a string\n                    in range=] steps with |query| |parsedValues|'s\n                    [=text directive/end=], |searchRange| |rangeEndSearchRange|,\n                    |wordStartBounded| true, |wordEndBounded|\n                    |mustEndAtWordBoundary| and |matchMustBeAtBeginning| false.\n                1. If |endMatch| is null then return null.\n                1. Set |potentialMatch|'s [=range/end=] to |endMatch|'s\n                    [=range/end=].\n            1. [=/Assert=]: |potentialMatch| is non-null, not [=range/collapsed=] and\n                represents a range exactly containing an instance of matching text.\n            1. If |parsedValues|'s [=text directive/suffix=] is null, return\n                |potentialMatch|.\n            1. Let |suffixRange| be a [=range=] with [=range/start=] equal to\n                |potentialMatch|'s [=range/end=] and [=range/end=] equal to\n                |searchRange|'s [=range/end=].\n            1. Advance |suffixRange|'s [=range/start=] to the [=next non-whitespace\n                position=].\n            1. Let |suffixMatch| be result of running the [=find a string in range=]\n                steps with |query| |parsedValues|'s [=text directive/suffix=],\n                |searchRange| |suffixRange|, |wordStartBounded| false,\n                |wordEndBounded| true and |matchMustBeAtBeginning| true.\n            1. If |suffixMatch| is non-null, return |potentialMatch|.\n            1. If |parsedValues|'s [=text directive/end=] item is null and\n                |suffixMatch| is null, then [=iteration/break=];\n                <div class=\"note\">\n                  If this is an exact match and the suffix doesn't match,\n                  start searching for the next range start by breaking out\n                  of this loop without |rangeEndSearchRange| being collapsed.\n                  If we're looking for a range match, we'll continue iterating\n                  this inner loop since the range start will already be correct.\n                </div>\n            1. Set |rangeEndSearchRange|'s [=range/start=] to |potentialMatch|'s\n                [=range/end=].\n                <div class=\"note\">\n                  Otherwise, it is possible that we found the correct range\n                  start, but not the correct range end. Continue the inner\n                  loop to keep searching for another matching instance of\n                  rangeEnd.\n                </div>\n        1. If |rangeEndSearchRange| is [=range/collapsed=] then:\n            1. [=/Assert=]: |parsedValues|'s [=text directive/end=] item is non-null\n            1. Return null\n                <div class=\"note\">\n                    This can only happen for range matches due to the\n                    [=iteration/break=] for exact matches in step 9 of the\n                    above loop. If we couldn't find a valid rangeEnd+suffix\n                    pair anywhere in the doc then there's no possible way to\n                    make a match.\n                </div>\n    1. Return null\n  </ol>\n\n</div>\n\n<wpt>\n  /scroll-to-text-fragment/find-range-from-text-directive.html\n</wpt>\n\n<div algorithm=\"advance range start to next non-whitespace position\">\nTo advance a [=range=] |range|'s [=range/start=] to the <dfn>next\nnon-whitespace position</dfn> follow the steps:\n\n  <ol class=\"algorithm\">\n    1. While |range| is not collapsed:\n        1. Let |node| be |range|'s [=range/start node=].\n        1. Let |offset| be |range|'s [=range/start offset=].\n        1. If |node| is part of a [=non-searchable subtree=] or if |node| is\n            not a [=visible text node=] or if |offset| is equal to |node|'s [=Node/length=] then:\n            1. Set |range|'s [=range/start node=] to the next node, in [=shadow-including tree order=].\n            1. Set |range|'s [=range/start offset=] to 0.\n            1. [=iteration/Continue=].\n        1. If the [=Text/substring data=] of |node| at offset |offset|\n            and count 6 is equal to the string \"&amp;nbsp;\" then:\n            1. Add 6 to |range|'s [=range/start offset=].\n        1. Otherwise, if the [=Text/substring data=] of |node| at offset |offset|\n            and count 5 is equal to the string \"&amp;nbsp\" then:\n            1. Add 5 to |range|'s [=range/start offset=].\n        1. Otherwise:\n            1. Let |cp| be the [=code point=] at the |offset| index in |node|'s\n                [=CharacterData/data=].\n            1. If |cp| does not have the <a\n                href=\"http://www.unicode.org/reports/tr44/#White_Space\">White_Space</a>\n                property set, return.\n            1. Add 1 to |range|'s [=range/start offset=].\n  </ol>\n</div>\n\n<div algorithm=\"find a string in a range\">\nTo <dfn>find a string in range</dfn> given a <a spec=infra>string</a> |query|, a\n[=range=] |searchRange|, and booleans |wordStartBounded|, |wordEndBounded| and\n|matchMustBeAtBeginning|, run these steps:\n\n<div class=\"note\">\n  This algorithm will return a [=range=] that represents the first instance of\n  the |query| text that is fully contained within |searchRange|, optionally\n  restricting itself to matches that start and/or end at word boundaries (see\n  [[#word-boundaries]]). Returns null if none is found.\n</div>\n\n<div class=\"note\">\n  <p>\n    The basic premise of this algorithm is to walk all searchable text nodes\n    within a block, collecting them into a list. The list is then concatenated\n    into a single string in which we can search, using the node list to\n    determine offsets with a node so we can return a [=range=].\n  </p>\n\n  <p>\n    Collection breaks when we hit a block node, e.g. searching over this tree:\n\n    ```\n      <div>\n        a<em>b</em>c<div>d</div>e\n      </div>\n    ```\n  </p>\n\n  Will perform a search on \"abc\", then on \"d\", then on \"e\".\n\n  Thus, |query| will only match text that is continuous (i.e. uninterrupted by\n  a block-level container) within a single block-level container.\n</div>\n\n  <ol class=\"algorithm\">\n    1. While |searchRange| is not [=range/collapsed=]:\n        1. Let |curNode| be |searchRange|'s [=range/start node=].\n        1. If |curNode| is part of a [=non-searchable subtree=]:\n            1. Set |searchRange|'s [=range/start node=] to the next node, in\n                [=shadow-including tree order=], that isn't a [=shadow-including\n                descendant=] of |curNode|.\n            1. Set |searchRange|'s [=range/start offset=] to 0.\n            1. [=iteration/Continue=].\n        1. If |curNode| is not a [=visible text node=]:\n            1. Set |searchRange|'s [=range/start node=] to the next node, in\n                [=shadow-including tree order=], that is not a [=doctype=].\n            1. Set |searchRange|'s [=range/start offset=] to 0.\n            1. [=iteration/Continue=].\n        1. Let |blockAncestor| be the [=nearest block ancestor=] of |curNode|.\n        1. Let |textNodeList| be a <a spec=infra>list</a> of {{Text}} nodes,\n            initially empty.\n        1. While |curNode| is a [=shadow-including descendant=] of |blockAncestor|\n            and the position of the [=/boundary point=] (|curNode|, 0) is not\n            [=boundary point/after=] |searchRange|'s [=range/end=]:\n            1. If |curNode| [=has block-level display=] then [=iteration/break=].\n            1. If |curNode| is [=search invisible=]:\n                1. Set |curNode| to the next node, in [=shadow-including tree\n                    order=], that isn't a [=shadow-including descendant=] of\n                    |curNode|.\n                2. [=iteration/Continue=].\n            1. If |curNode| is a [=visible text node=] then append it to\n                |textNodeList|.\n            1. Set |curNode| to the next node in [=shadow-including tree order=].\n        1. Run the [=find a range from a node list=] steps given |query|,\n            |searchRange|, |textNodeList|, |wordStartBounded|, |wordEndBounded|\n            and |matchMustBeAtBeginning| as input. If the resulting [=range=]\n            is not null, then return it.\n        1. If |matchMustBeAtBeginning| is true, return null.\n        1. If |curNode| is null, then [=iteration/break=].\n        1. [=/Assert=]: |curNode| [=tree/following|follows=] |searchRange|'s\n            [=range/start node=].\n        1. Set |searchRange|'s [=range/start=] to the [=/boundary point=] (|curNode|,\n            0).\n    1. Return null.\n  </ol>\n</div>\n\nA node is <dfn>search invisible</dfn> if it is an [=element=] in the [=HTML\nnamespace=] and meets any of the following conditions:\n1. The [=computed value=] of its 'display' property is ''display/none''.\n1. If the node <a spec=html>serializes as void</a>.\n1. Is any of the following types: {{HTMLIFrameElement}}, {{HTMLImageElement}},\n    {{HTMLMeterElement}}, {{HTMLObjectElement}}, {{HTMLProgressElement}},\n    {{HTMLStyleElement}}, {{HTMLScriptElement}}, {{HTMLVideoElement}},\n    {{HTMLAudioElement}}\n1. Is a <{select}> element whose <{select/multiple}> content attribute is absent.\n\nA node is part of a <dfn>non-searchable subtree</dfn> if it is or has a\n[=shadow-including ancestor=] that is [=search invisible=].\n\nA node is a <dfn>visible text node</dfn> if it is a {{Text}} node, the\n[=computed value=] of its [=parent element=]'s 'visibility' property is\n''visibility/visible'', and it is <a spec=html>being rendered</a>.\n\nA node <dfn>has block-level display</dfn> if it is an [=element=] and the [=computed value=] of its\n'display' property is any of ''display/block'', ''display/table'',\n''display/flow-root'', ''display/grid'', ''display/flex'',\n''display/list-item''.\n\n<div algorithm=\"nearest block ancestor\">\nTo find the <dfn>nearest block ancestor</dfn> of a |node| follow the steps:\n  <ol class=\"algorithm\">\n    1. Let |curNode| be |node|.\n    1. While |curNode| is non-null\n        1. If |curNode| is not a {{Text}} node and it [=has block-level display=] then\n            return |curNode|.\n        1. Otherwise, set |curNode| to |curNode|'s [=tree/parent=].\n    1. Return |node|'s [=Node/node document=]'s [=document element=].\n  </ol>\n</div>\n\n<div algorithm=\"range from node list\">\nTo <dfn>find a range from a node list</dfn> given a search string |queryString|,\na [=range=] |searchRange|, a [=/list=] of {{Text}} nodes |nodes|, and booleans\n|wordStartBounded|, |wordEndBounded| and |matchMustBeAtBeginning|, follow these steps:\n\n<div class=\"note\">\n  Optionally, this will only return a match if the matched text begins and/or\n  ends on a [=word boundary=]. For example:\n\n  <div class=\"example\">\n    The query string “range” will always match in “mountain range”, but\n    1. When requiring a word boundary at the beginning, it will not match in “color orange”.\n    2. When requiring a word boundary at the end, it will not match in “forest ranger”.\n  </div>\n\n  See [[#word-boundaries]] for details and more examples.\n</div>\n<div class=\"note\">\n  Optionally, this will only return a match if the matched text is at the beginning\n  of the node list.\n</div>\n\n  <ol class=\"algorithm\">\n    1. Let |searchBuffer| be the [=string/concatenate|concatenation=] of the\n        [=CharacterData/data=] of each item in |nodes|.\n\n        ISSUE(WICG/scroll-to-text-fragment#98): [=CharacterData/data=] is not\n        correct here since that's the text data as it exists in the DOM. This\n        algorithm means to run over the text as rendered (and then convert back\n        to Ranges in the DOM).\n    1. Let |searchStart| be 0.\n    1. If the first item in |nodes| is |searchRange|'s [=range/start node=] then\n        set |searchStart| to |searchRange|'s [=range/start offset=].\n    1. Let |start| and |end| be [=/boundary points=], initially null.\n    1. Let |matchIndex| be null.\n    1. While |matchIndex| is null\n        1. Set |matchIndex| to the index of the first instance of |queryString| in\n            |searchBuffer|, starting at |searchStart|. The string search must be\n            performed using a base character comparison, or the\n            <a href=\"http://www.unicode.org/reports/tr10/#Multi_Level_Comparison\">primary\n            level</a>, as defined in [[!UTS10]].\n            <div class=\"note\">\n              Intuitively, this is a case-insensitive search also ignoring accents, umlauts,\n              and other marks.\n            </div>\n        1. If |matchIndex| is null, return null.\n        1. If |matchMustBeAtBeginning| is true and |matchIndex| is not 0, return null.\n        1. Let |endIx| be |matchIndex| + |queryString|'s [=string/length=].\n            <div class=\"note\">\n               |endIx| is the index of the last character in the match + 1.\n            </div>\n        1. Set |start| to the [=/boundary point=] result of [=get boundary point at\n            index=] |matchIndex| run over |nodes| with |isEnd| false.\n        1. Set |end| to the [=/boundary point=] result of [=get boundary point at\n            index=] |endIx| run over |nodes| with |isEnd| true.\n        1. If |wordStartBounded| is true and |matchIndex| [=is at a word boundary|is\n            not at a word boundary=] in |searchBuffer|, given the <a\n            spec=html>language</a> from |start|'s [=boundary point/node=] as the\n            |locale|; or |wordEndBounded| is true and |matchIndex| + |queryString|'s\n            [=string/length=] [=is at a word boundary|is not at a word boundary=] in\n            |searchBuffer|, given the <a spec=html>language</a> from |end|'s\n            [=boundary point/node=] as the |locale|:\n            1. Set |searchStart| to |matchIndex| + 1.\n            1. Set |matchIndex| to null.\n    1. Let |endInset| be 0.\n    1. If the last item in |nodes| is |searchRange|'s [=range/end node=] then set\n        |endInset| to (|searchRange|'s [=range/end node=]'s [=Node/length=] &minus;\n        |searchRange|'s [=range/end offset=])\n        <div class=\"note\">\n          |endInset| is the offset from the last position in the last node in the\n          reverse direction. Alternatively, it is the length of the node that's not\n          included in the range.\n        </div>\n    1. If |matchIndex| + |queryString|'s [=string/length=] is greater than\n        |searchBuffer|'s length &minus; |endInset| return null.\n        <div class=\"note\">\n          If the match runs past the end of the search range, return null.\n        </div>\n    1. [=/Assert=]: |start| and |end| are non-null, valid [=/boundary points=] in\n        |searchRange|.\n    1. Return a [=range=] with [=range/start=] |start| and [=range/end=] |end|.\n  </ol>\n</div>\n\n<div algorithm=\"boundary point at index\">\nTo <dfn>get boundary point at index</dfn>, given an integer |index|, [=/list=]\nof {{Text}} nodes |nodes|, and a boolean |isEnd|, follow these steps:\n\n<div class=\"note\">\n  <p>\n    This is a small helper routine used by the steps above to determine which\n    node a given index in the concatenated string belongs to.\n  </p>\n  <p>\n    |isEnd| is used to differentiate start and end indices. An end index points\n    to the \"one-past-last\" character of the matching string. If the match ends\n    at node boundary, we want the end offset to remain within that node, rather\n    than the start of the next node.\n  </p>\n</div>\n\n  <ol class=\"algorithm\">\n    1. Let |counted| be 0.\n    1. For each |curNode| of |nodes|:\n        1. Let |nodeEnd| be |counted| + |curNode|'s [=Node/length=].\n        1. If |isEnd| is true, add 1 to |nodeEnd|.\n        1. If |nodeEnd| is greater than |index| then:\n            1. Return the [=/boundary point=] (|curNode|, |index| &minus; |counted|).\n        1. Increment |counted| by |curNode|'s [=Node/length=].\n    1. Return null.\n  </ol>\n</div>\n\n### Word Boundaries ### {#word-boundaries}\n<div class=\"note\">\n  Limiting matching to word boundaries is one of the mitigations to limit\n  cross-origin information leakage.\n</div>\n<div class=\"note\">\n  See <a\n  href=\"https://github.com/tc39/proposal-intl-segmenter\">Intl.Segmenter</a>, a\n  proposal to specify unicode segmentation, including word segmentation. Once\n  specified, this algorithm can be improved by making use of the Intl.Segmenter\n  API for word boundary matching.\n</div>\n\n<p>\n  A <dfn>word boundary</dfn> is defined in [[!UAX29]] in\n  [[UAX29#Word_Boundaries]]. [[UAX29#Default_Word_Boundaries]] defines a\n  default set of what constitutes a word boundary, but as the specification\n  mentions, a more sophisticated algorithm should be used based on the locale.\n</p>\n<p>\n  Dictionary-based word bounding should take specific care in locales without a\n  word-separating character. E.g. In English, words are separated by the space\n  character (' '); however, in Japanese there is no character that separates one\n  word from the next. In such cases, and where the alphabet contains fewer\n  than 100 characters, the dictionary must not contain more than 20% of the\n  alphabet as valid, one-letter words.\n</p>\n\nA <dfn>locale</dfn> is a <a spec=infra>string</a> containing a valid [[BCP47]]\nlanguage tag, or the empty string. An empty string indicates that the primary\nlanguage is unknown.\n\nA substring is <dfn>word bounded</dfn> in a <a spec=infra>string</a> |text|,\ngiven [=locales=] |startLocale| and |endLocale|, if both the position of its\nfirst character [=is at a word boundary=] given |startLocale|, and the position\nafter its last character [=is at a word boundary=] given |endLocale|.\n\nA number |position| <dfn>is at a word boundary</dfn> in a <a spec=infra>string</a>\n|text|, given a [=locale=] |locale|, if, using |locale|, either a [=word\nboundary=] immediately precedes the |position|th code unit, or |text|'s length\nis more than 0 and |position| equals either 0 or |text|'s length.\n\n<div class=\"note\">\n  Intuitively, a substring is [=word bounded=] if it neither begins nor ends in\n  the middle of a word.\n\n  In languages with a word separator (e.g. \" \" space) this is (mostly)\n  straightforward; though there are details covered by the above technical\n  reports such as new lines, hyphenations, quotes, etc.\n\n  Some languages do not have such a separator (notably,\n  Chinese/Japanese/Korean). Languages such as these requires dictionaries to\n  determine what a valid word in the given locale is.\n</div>\n\n<div class=\"example\">\n  <p>\n    Text fragments are restricted such that match terms, when combined with\n    their adjacent context terms, are word bounded. For example, in an\n    exact search like <code>prefix,start,suffix</code>,\n    <code>\"prefix+start+suffix\"</code> will match only if the entire result is word bounded. However, in a\n    range search like <code>prefix,start,end,suffix</code>, a match is\n    found only if both\n    <code>\"prefix+start\"</code> and <code>\"end+suffix\"</code> are\n    word bounded.\n  </p>\n\n  <p>\n    The goal is that a third-party must already know the full tokens they are\n    matching against. A range match like <code>start,end</code> must be\n    word bounded on the inside of the two terms; otherwise a third party could\n    use this repeatedly to try and reveal a token (e.g. on a page with\n    <code>\"Balance: 123,456 $\"</code>, a third-party could set\n    <code>prefix=\"Balance: \", end=\"$\"</code> and vary <code>start</code>\n    to try and guess the numeric token one digit at a time).\n  </p>\n\n  <p>\n    For more details, refer to the [Security Review Doc](https://docs.google.com/document/d/1YHcl1-vE_ZnZ0kL2almeikAj2gkwCq8_5xwIae7PVik/edit#heading=h.78iny7nejmx2)\n  </p>\n</div>\n\n<div class=\"example\">\n  The substring \"mountain range\" is word bounded within the string \"An impressive\n  mountain range\" but not within \"An impressive mountain ranger\".\n</div>\n\n<div class=\"example\">\n  In the Japanese string \"<span lang=\"ja\">ウィキペディアへようこそ</span>\" (Welcome to Wikipedia),\n  \"<span lang=\"ja\">ようこそ</span>\" (Welcome) is considered word-bounded but \"<span lang=\"ja\">ようこ</span>\" is not.\n</div>\n\n## Indicating The Text Match ## {#indicating-the-text-match}\n\nThe UA may choose to scroll the text fragment into view as part of the <a\nspec=HTML>try to scroll to the fragment</a> steps or by some other mechanism;\nhowever, it is not required to scroll the match into view.\n\nThe UA should visually indicate the matched text in some way such that the user\nis made aware of the text match, such as with a high-contrast highlight.\n\nThe UA should provide to the user some method of dismissing the match, such\nthat the matched text no longer appears visually indicated.\n\nThe exact appearance and mechanics of the indication are left as UA-defined.\nHowever, the UA must not use any methods observable by author script, such as\nthe Document's <a href=\"https://w3c.github.io/selection-api/#dfn-selection\">\nselection</a>, to indicate the text match. Doing so could allow attack vectors\nfor content exfiltration.\n\nThe UA must not visually indicate any provided context terms.\n\nSince the indicator is not part of the document's content, UAs should consider\nways to differentiate it from the page's content as perceived by the user.\n\n<div class=\"example\">\n  The UA could provide an in-product help prompt the first few times the\n  indicator appears to help train the user that it comes from the linking page\n  and is provided by the UA.\n</div>\n\n### URLs in UA features ### {#urls-in-ua-features}\n\nUAs provide a number of consumers for a document's URL (outside of programmatic\nAPIs like <code>window.location</code>). Examples include a location bar\nindicating the URL of the currently visible document, or the URL used when a\nuser requests to create a bookmark for the current page.\n\nTo avoid user confusion, UAs should be consistent in whether such URLs include\nthe [=/fragment directive=]. This section provides a default set of\nrecommendations for how UAs can handle these cases.\n\n<div class='note'>\n  <p>\n  We provide these as a baseline for consistent behavior; however, as these\n  features don't affect cross-UA interoperability, they are not strict\n  conformance requirements.\n  </p>\n\n  <p>\n  Exact behavior is left up to the implementing UA which can have differing\n  constraints or reasons for modifying the behavior. e.g. UAs can allow users\n  to configure defaults or expose UI options so users can choose whether they\n  prefer to include fragment directives in these URLs.\n\n  It's also useful to allow UAs to experiment with providing a better\n  experience. E.g. perhaps the UA's displayed URL can elide the text fragment if\n  the user scrolls it out of view?\n  </p>\n</div>\n\nThe general principle is that a URL should include the [=/fragment directive=]\nonly while the visual indicator is visible (i.e. not dismissed). If the user\ndismisses the indicator, the URL should reflect that by also removing the the\n[=/fragment directive=].\n\nIf the URL includes a text fragment but a match wasn't found in the current\npage, the UA may choose to omit it from the exposed URL.\n\n<div class='note'>\n  <p>\n  A text fragment that isn't found on the page can be useful information to\n  surface to a user to indicate that the page has changed since the link\n  was created.\n  </p>\n\n  <p>\n  However, it's unlikely to be useful to the user in a bookmark.\n  </p>\n</div>\n\nA few common examples are provided below.\n\n<div class='note'>\n  We use \"text fragment\" and \"fragment directive\" interchangeably here as text\n  fragments are assumed to be the only kind of directive. If additional\n  directives are added in the future, the UX in these cases will have to be\n  re-evaluated separately for new directive types.\n</div>\n\n#### Location Bar #### {#urls-in-location-bar}\n\nThe location bar's URL should include a text fragment while it is visually\nindicated. The [=/fragment directive=] should be stripped from the location bar\nURL when the user dismisses the indication.\n\nIt is recommended that the text fragment be displayed in the location bar's URL\neven if a match wasn't located in the document.\n\n#### Bookmarks #### {#urls-in-bookmarks}\n\nMany UAs provide a \"bookmark\" feature allowing users to store a convenient link\nto the current page in the UA's interface.\n\nA newly created bookmark should, by default, include the [=/fragment directive=]\nin the URL if, and only if, a match was found and the visual indicator hasn't\nbeen dismissed.\n\nNavigating to a URL from a bookmark should process a [=/fragment directive=] as\nif it were navigated to in a typical navigation.\n\n#### Sharing #### {#urls-in-sharing}\n\nSome UAs provide a method for users to share the current page with others,\ntypically by providing the URL to another app or messaging service.\n\nWhen providing a URL in these situations, it should include the [=/fragment\ndirective=] if, and only if, a match was found and the visual indicator hasn't\nbeen dismissed.\n\n## Document Policy Integration ## {#document-policy-integration}\n\n<!-- TODO:Replace manual links with autolinks to document-policy definitions\n          once it's referrable.  Also remember to autolink the ref in the\n          navigating-to-text-fragment section -->\n\nThis specification defines a <a href=\"https://wicg.github.io/document-policy#configuration-point\">configuration point</a>\nin [[!document-policy|Document Policy]] with name \"force-load-at-top\". Its\n<a href=\"https://wicg.github.io/document-policy#configuration-point-type\">type</a> is `boolean`\nwith <a href=\"https://wicg.github.io/document-policy#configuration-point-default-value\">default value</a>\n`false`.\n\n<div class=\"note\">\n  When enabled, this policy disables all automatic scroll-on-load features:\n  text-fragments, element fragments, history scroll restoration.\n</div>\n<div class='example'>\n  Suppose the user navigates to `https://example.com#:~:text=foo`. The\n  example.com server response includes the header:\n\n  ```\n  Document-Policy: force-load-at-top\n  ```\n\n  When the page loads, the element containing \"foo\" will be marked as the\n  indicated part and set as the document's target element. However, \"foo\"\n  will not be scrolled into view.\n</div>\n\nFragment-based scroll blocking from this policy is specified in an amendment to the\n<a spec=HTML>scroll to the fragment</a> algorithm in the\n[[#navigating-to-text-fragment]] section of this document.\n\nHistory scroll restoration is blocked by amending the <a spec=\"HTML\">restore\npersisted state</a> steps by inserting a new step after 2:\n\n3. <a href=\"https://wicg.github.io/document-policy#algo-get-policy-value\">Get\n    the document policy value</a> of the \"force-load-at-top\" feature for the [=/Document=]. If\n    the result is true, then the user agent should not restore the scroll\n    position for the [=/Document=] or any of its scrollable regions.\n\n\n## Feature Detectability ## {#feature-detectability}\n\nFor feature detectability, we propose adding a new FragmentDirective interface\nthat is exposed via <code>document.fragmentDirective</code> if the UA supports\nthe feature.\n\n<pre class='idl'>\n  [Exposed=Window]\n  interface FragmentDirective {\n  };\n</pre>\n\nWe amend the {{Document}} interface to include a <code>fragmentDirective</code>\nproperty:\n\n<pre class='idl'>\n  partial interface Document {\n      [SameObject] readonly attribute FragmentDirective fragmentDirective;\n  };\n</pre>\n\nThis object may be used to expose additional information about the text\nfragment or other fragment directives in the future.\n\n# Generating Text Fragment Directives # {#generating-text-fragment-directives}\n\n<div class='note'>\n  This section is non-normative.\n</div>\n\nThis section contains recommendations for UAs automatically generating URLs\nwith a [=text directive=]. These recommendations aren't normative but\nare provided to ensure generated URLs result in maximally stable and usable\nURLs.\n\n## Prefer Exact Matching To Range-based ## {#prefer-exact-matching-to-range-based}\n\nThe match text can be provided either as an exact string \"text=foo%20bar%20baz\"\nor as a range \"text=foo,bar\".\n\nPrefer to specify the entire string where practical. This ensures that if the\ndestination page is removed or changed, the intended destination can still be\nderived from the URL itself.\n\n<div class='example'>\n  Suppose we wish to craft a URL to\n  https://en.wikipedia.org/wiki/History_of_computing quoting the sentence:\n\n  <pre>\n    The first recorded idea of using digital electronics for computing was the\n    1931 paper \"The Use of Thyratrons for High Speed Automatic Counting of\n    Physical Phenomena\" by C. E. Wynn-Williams.\n  </pre>\n\n  We could create a range-based match like so:\n\n  <a href=\"https://en.wikipedia.org/wiki/History_of_computing#:~:text=The%20first%20recorded,Williams\">\n  https://en.wikipedia.org/wiki/History_of_computing#:~:text=The%20first%20recorded,Williams</a>\n\n  Or we could encode the entire sentence using an exact match term:\n\n  <a href=\"https://en.wikipedia.org/wiki/History_of_computing#:~:text=The%20first%20recorded%20idea%20of%20using%20digital%20electronics%20for%20computing%20was%20the%201931%20paper%20%22The%20Use%20of%20Thyratrons%20for%20High%20Speed%20Automatic%20Counting%20of%20Physical%20Phenomena%22%20by%20C.%20E.%20Wynn-Williams\">\n  https://en.wikipedia.org/wiki/History_of_computing#:~:text=The%20first%20recorded%20idea%20of%20using%20digital%20electronics%20for%20computing%20was%20the%201931%20paper%20%22The%20Use%20of%20Thyratrons%20for%20High%20Speed%20Automatic%20Counting%20of%20Physical%20Phenomena%22%20by%20C.%20E.%20Wynn-Williams</a>\n\n  The range-based match is less stable, meaning that if the page is changed to\n  include another instance of \"The first recorded\" somewhere earlier in the\n  page, the link will now target an unintended text snippet.\n\n  The range-based match is also less useful semantically. If the page is\n  changed to remove the sentence, the user won't know what the intended\n  target was. In the exact match case, the user can read, or the UA can\n  surface, the text that was being searched for but not found.\n</div>\n\nRange-based matches can be helpful when the quoted text is excessively long\nand encoding the entire string would produce an unwieldy URL.\n\nText snippets shorter than 300 characters are encouraged to be encoded using an\nexact match. Above this limit, the UA can encode the string as a range-based\nmatch.\n\n<div class='note'>\n  TODO:  Can we determine the above limit in some less arbitrary way?\n</div>\n\n## Use Context Only When Necessary ## {#use-context-only-when-necessary}\n\nContext terms allow the [=text directive=] to disambiguate text\nsnippets on a page. However, their use can make the URL more brittle in some\ncases. Often, the desired string will start or end at an element boundary. The\ncontext will therefore exist in an adjacent element. Changes to the page\nstructure could invalidate the [=text directive=] since the context and\nmatch text will no longer appear to be adjacent.\n\n<div class='example'>\n  Suppose we wish to craft a URL for the following text:\n\n  <pre>\n    &lt;div class=\"section\"&gt;HEADER&lt;/div&gt;\n    &lt;div class=\"content\"&gt;Text to quote&lt;/div&gt;\n  </pre>\n\n  We could craft the [=text directive=] as follows:\n\n  <pre>\n    text=HEADER-,Text%20to%20quote\n  </pre>\n\n  However, suppose the page changes to add a \"[edit]\" link beside all section\n  headers. This would now break the URL.\n</div>\n\nWhere a text snippet is long enough and unique, a UAs are encouraged to avoid\nadding superfluous context terms.\n\nUse context only if one of the following is true:\n<ul>\n  <li>The UA determines the quoted text is ambiguous</li>\n  <li>The quoted text contains 3 or fewer words</li>\n</ul>\n\n<div class=\"note\">\n  TODO: Determine the numeric limit above in less arbitrary way.\n</div>\n\n## Determine If Fragment Id Is Needed ## {#determine-if-fragment-id-is-needed}\n\nWhen the UA navigates to a URL containing a [=text directive=], it will\nfallback to scrolling into view a regular element-id based fragment if it\nexists and the text fragment isn't found.\n\nThis can be useful to provide a fallback, in case the text in the document\nchanges, invalidating the [=text directive=].\n\n<div class='example'>\n  Suppose we wish to craft a URL to\n  https://en.wikipedia.org/wiki/History_of_computing quoting the sentence:\n\n  <pre>\n    The earliest known tool for use in computation is the Sumerian abacus\n  </pre>\n\n  By specifying the section that the text appears in, we ensure that, if the\n  text is changed or removed, the user will still be pointed to the relevant\n  section:\n\n  <a href=\"https://en.wikipedia.org/wiki/History_of_computing#Early_computation:~:text=The%20earliest%20known%20tool%20for%20use%20in%20computation%20is%20the%20Sumerian%20abacus\">\n  https://en.wikipedia.org/wiki/History_of_computing#Early_computation:~:text=The%20earliest%20known%20tool%20for%20use%20in%20computation%20is%20the%20Sumerian%20abacus</a>\n</div>\n\nHowever, UAs should take care that the fallback element-id fragment is the\ncorrect one:\n\n<div class='example'>\n  Suppose the user navigates to\n  https://en.wikipedia.org/wiki/History_of_computing#Early_computation. They\n  now scroll down to the Symbolic Computations section. There, they select a\n  text snippet and choose to create a URL to it:\n\n  <pre>\n    By the late 1960s, computer systems could perform symbolic algebraic\n    manipulations\n  </pre>\n\n  Even though the current URL of the page is:\n  https://en.wikipedia.org/wiki/History_of_computing#Early_computation, using\n  #Early_computation as a fallback is inappropriate. If the above sentence is\n  changed or removed, the page will load in the #Early_computation section\n  which could be quite confusing to the user.\n\n  If the UA cannot reliably determine an appropriate fragment to fallback to,\n  it should remove the fragment id from the URL:\n\n  <a href=\"https://en.wikipedia.org/wiki/History_of_computing#:~:text=By%20the%20late%201960s,%20computer%20systems%20could%20perform%20symbolic%20algebraic%20manipulations\">\n  https://en.wikipedia.org/wiki/History_of_computing#:~:text=By%20the%20late%201960s,%20computer%20systems%20could%20perform%20symbolic%20algebraic%20manipulations</a>\n</div>\n"
  },
  {
    "path": "index.html",
    "content": "<!doctype html><html lang=\"en\">\n <head>\n  <meta content=\"text/html; charset=utf-8\" http-equiv=\"Content-Type\">\n  <title>URL Fragment Text Directives</title>\n  <meta content=\"width=device-width, initial-scale=1, shrink-to-fit=no\" name=\"viewport\">\n  <link href=\"https://www.w3.org/StyleSheets/TR/2021/cg-draft\" rel=\"stylesheet\">\n  <meta content=\"Bikeshed version 82ce88815, updated Thu Sep 7 16:33:55 2023 -0700\" name=\"generator\">\n  <link href=\"https://wicg.github.io/scroll-to-text-fragment/\" rel=\"canonical\">\n<style>\n  .monkeypatch {\n    color: grey;\n  }\n\n  .monkeypatch .diff {\n    color: var(--text);\n  }\n</style>\n<style>/* Boilerplate: style-autolinks */\n.css.css, .property.property, .descriptor.descriptor {\n    color: var(--a-normal-text);\n    font-size: inherit;\n    font-family: inherit;\n}\n.css::before, .property::before, .descriptor::before {\n    content: \"‘\";\n}\n.css::after, .property::after, .descriptor::after {\n    content: \"’\";\n}\n.property, .descriptor {\n    /* Don't wrap property and descriptor names */\n    white-space: nowrap;\n}\n.type { /* CSS value <type> */\n    font-style: italic;\n}\npre .property::before, pre .property::after {\n    content: \"\";\n}\n[data-link-type=\"property\"]::before,\n[data-link-type=\"propdesc\"]::before,\n[data-link-type=\"descriptor\"]::before,\n[data-link-type=\"value\"]::before,\n[data-link-type=\"function\"]::before,\n[data-link-type=\"at-rule\"]::before,\n[data-link-type=\"selector\"]::before,\n[data-link-type=\"maybe\"]::before {\n    content: \"‘\";\n}\n[data-link-type=\"property\"]::after,\n[data-link-type=\"propdesc\"]::after,\n[data-link-type=\"descriptor\"]::after,\n[data-link-type=\"value\"]::after,\n[data-link-type=\"function\"]::after,\n[data-link-type=\"at-rule\"]::after,\n[data-link-type=\"selector\"]::after,\n[data-link-type=\"maybe\"]::after {\n    content: \"’\";\n}\n\n[data-link-type].production::before,\n[data-link-type].production::after,\n.prod [data-link-type]::before,\n.prod [data-link-type]::after {\n    content: \"\";\n}\n\n[data-link-type=element],\n[data-link-type=element-attr] {\n    font-family: Menlo, Consolas, \"DejaVu Sans Mono\", monospace;\n    font-size: .9em;\n}\n[data-link-type=element]::before { content: \"<\" }\n[data-link-type=element]::after  { content: \">\" }\n\n[data-link-type=biblio] {\n    white-space: pre;\n}\n\n@media (prefers-color-scheme: dark) {\n    :root {\n        --selflink-text: black;\n        --selflink-bg: silver;\n        --selflink-hover-text: white;\n    }\n}\n</style>\n<style>/* Boilerplate: style-colors */\n\n/* Any --*-text not paired with a --*-bg is assumed to have a transparent bg */\n:root {\n    color-scheme: light dark;\n\n    --text: black;\n    --bg: white;\n\n    --unofficial-watermark: url(https://www.w3.org/StyleSheets/TR/2016/logos/UD-watermark);\n\n    --logo-bg: #1a5e9a;\n    --logo-active-bg: #c00;\n    --logo-text: white;\n\n    --tocnav-normal-text: #707070;\n    --tocnav-normal-bg: var(--bg);\n    --tocnav-hover-text: var(--tocnav-normal-text);\n    --tocnav-hover-bg: #f8f8f8;\n    --tocnav-active-text: #c00;\n    --tocnav-active-bg: var(--tocnav-normal-bg);\n\n    --tocsidebar-text: var(--text);\n    --tocsidebar-bg: #f7f8f9;\n    --tocsidebar-shadow: rgba(0,0,0,.1);\n    --tocsidebar-heading-text: hsla(203,20%,40%,.7);\n\n    --toclink-text: var(--text);\n    --toclink-underline: #3980b5;\n    --toclink-visited-text: var(--toclink-text);\n    --toclink-visited-underline: #054572;\n\n    --heading-text: #005a9c;\n\n    --hr-text: var(--text);\n\n    --algo-border: #def;\n\n    --del-text: red;\n    --del-bg: transparent;\n    --ins-text: #080;\n    --ins-bg: transparent;\n\n    --a-normal-text: #034575;\n    --a-normal-underline: #bbb;\n    --a-visited-text: var(--a-normal-text);\n    --a-visited-underline: #707070;\n    --a-hover-bg: rgba(75%, 75%, 75%, .25);\n    --a-active-text: #c00;\n    --a-active-underline: #c00;\n\n    --blockquote-border: silver;\n    --blockquote-bg: transparent;\n    --blockquote-text: currentcolor;\n\n    --issue-border: #e05252;\n    --issue-bg: #fbe9e9;\n    --issue-text: var(--text);\n    --issueheading-text: #831616;\n\n    --example-border: #e0cb52;\n    --example-bg: #fcfaee;\n    --example-text: var(--text);\n    --exampleheading-text: #574b0f;\n\n    --note-border: #52e052;\n    --note-bg: #e9fbe9;\n    --note-text: var(--text);\n    --noteheading-text: hsl(120, 70%, 30%);\n    --notesummary-underline: silver;\n\n    --assertion-border: #aaa;\n    --assertion-bg: #eee;\n    --assertion-text: black;\n\n    --advisement-border: orange;\n    --advisement-bg: #fec;\n    --advisement-text: var(--text);\n    --advisementheading-text: #b35f00;\n\n    --warning-border: red;\n    --warning-bg: hsla(40,100%,50%,0.95);\n    --warning-text: var(--text);\n\n    --amendment-border: #330099;\n    --amendment-bg: #F5F0FF;\n    --amendment-text: var(--text);\n    --amendmentheading-text: #220066;\n\n    --def-border: #8ccbf2;\n    --def-bg: #def;\n    --def-text: var(--text);\n    --defrow-border: #bbd7e9;\n\n    --datacell-border: silver;\n\n    --indexinfo-text: #707070;\n\n    --indextable-hover-text: black;\n    --indextable-hover-bg: #f7f8f9;\n\n    --outdatedspec-bg: rgba(0, 0, 0, .5);\n    --outdatedspec-text: black;\n    --outdated-bg: maroon;\n    --outdated-text: white;\n    --outdated-shadow: red;\n\n    --editedrec-bg: darkorange;\n}\n\n@media (prefers-color-scheme: dark) {\n    :root {\n        --text: #ddd;\n        --bg: black;\n\n        --unofficial-watermark: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='400'%3E%3Cg fill='%23100808' transform='translate(200 200) rotate(-45) translate(-200 -200)' stroke='%23100808' stroke-width='3'%3E%3Ctext x='50%25' y='220' style='font: bold 70px sans-serif; text-anchor: middle; letter-spacing: 6px;'%3EUNOFFICIAL%3C/text%3E%3Ctext x='50%25' y='305' style='font: bold 70px sans-serif; text-anchor: middle; letter-spacing: 6px;'%3EDRAFT%3C/text%3E%3C/g%3E%3C/svg%3E\");\n\n        --logo-bg: #1a5e9a;\n        --logo-active-bg: #c00;\n        --logo-text: white;\n\n        --tocnav-normal-text: #999;\n        --tocnav-normal-bg: var(--bg);\n        --tocnav-hover-text: var(--tocnav-normal-text);\n        --tocnav-hover-bg: #080808;\n        --tocnav-active-text: #f44;\n        --tocnav-active-bg: var(--tocnav-normal-bg);\n\n        --tocsidebar-text: var(--text);\n        --tocsidebar-bg: #080808;\n        --tocsidebar-shadow: rgba(255,255,255,.1);\n        --tocsidebar-heading-text: hsla(203,20%,40%,.7);\n\n        --toclink-text: var(--text);\n        --toclink-underline: #6af;\n        --toclink-visited-text: var(--toclink-text);\n        --toclink-visited-underline: #054572;\n\n        --heading-text: #8af;\n\n        --hr-text: var(--text);\n\n        --algo-border: #456;\n\n        --del-text: #f44;\n        --del-bg: transparent;\n        --ins-text: #4a4;\n        --ins-bg: transparent;\n\n        --a-normal-text: #6af;\n        --a-normal-underline: #555;\n        --a-visited-text: var(--a-normal-text);\n        --a-visited-underline: var(--a-normal-underline);\n        --a-hover-bg: rgba(25%, 25%, 25%, .2);\n        --a-active-text: #f44;\n        --a-active-underline: var(--a-active-text);\n\n        --borderedblock-bg: rgba(255, 255, 255, .05);\n\n        --blockquote-border: silver;\n        --blockquote-bg: var(--borderedblock-bg);\n        --blockquote-text: currentcolor;\n\n        --issue-border: #e05252;\n        --issue-bg: var(--borderedblock-bg);\n        --issue-text: var(--text);\n        --issueheading-text: hsl(0deg, 70%, 70%);\n\n        --example-border: hsl(50deg, 90%, 60%);\n        --example-bg: var(--borderedblock-bg);\n        --example-text: var(--text);\n        --exampleheading-text: hsl(50deg, 70%, 70%);\n\n        --note-border: hsl(120deg, 100%, 35%);\n        --note-bg: var(--borderedblock-bg);\n        --note-text: var(--text);\n        --noteheading-text: hsl(120, 70%, 70%);\n        --notesummary-underline: silver;\n\n        --assertion-border: #444;\n        --assertion-bg: var(--borderedblock-bg);\n        --assertion-text: var(--text);\n\n        --advisement-border: orange;\n        --advisement-bg: #222218;\n        --advisement-text: var(--text);\n        --advisementheading-text: #f84;\n\n        --warning-border: red;\n        --warning-bg: hsla(40,100%,20%,0.95);\n        --warning-text: var(--text);\n\n        --amendment-border: #330099;\n        --amendment-bg: #080010;\n        --amendment-text: var(--text);\n        --amendmentheading-text: #cc00ff;\n\n        --def-border: #8ccbf2;\n        --def-bg: #080818;\n        --def-text: var(--text);\n        --defrow-border: #136;\n\n        --datacell-border: silver;\n\n        --indexinfo-text: #aaa;\n\n        --indextable-hover-text: var(--text);\n        --indextable-hover-bg: #181818;\n\n        --outdatedspec-bg: rgba(255, 255, 255, .5);\n        --outdatedspec-text: black;\n        --outdated-bg: maroon;\n        --outdated-text: white;\n        --outdated-shadow: red;\n\n        --editedrec-bg: darkorange;\n    }\n    /* In case a transparent-bg image doesn't expect to be on a dark bg,\n       which is quite common in practice... */\n    img { background: white; }\n}\n</style>\n<style>/* Boilerplate: style-counters */\nbody {\n    counter-reset: example figure issue;\n}\n.issue {\n    counter-increment: issue;\n}\n.issue:not(.no-marker)::before {\n    content: \"Issue \" counter(issue);\n}\n\n.example {\n    counter-increment: example;\n}\n.example:not(.no-marker)::before {\n    content: \"Example \" counter(example);\n}\n.invalid.example:not(.no-marker)::before,\n.illegal.example:not(.no-marker)::before {\n    content: \"Invalid Example\" counter(example);\n}\n\nfigcaption {\n    counter-increment: figure;\n}\nfigcaption:not(.no-marker)::before {\n    content: \"Figure \" counter(figure) \" \";\n}\n</style>\n<style>/* Boilerplate: style-dfn-panel */\n:root {\n    --dfnpanel-bg: #ddd;\n    --dfnpanel-text: var(--text);\n}\n@media (prefers-color-scheme: dark) {\n    :root {\n        --dfnpanel-bg: #222;\n        --dfnpanel-text: var(--text);\n    }\n}\n.dfn-panel {\n    position: absolute;\n    z-index: 35;\n    width: 20em;\n    width: 300px;\n    height: auto;\n    max-height: 500px;\n    overflow: auto;\n    padding: 0.5em 0.75em;\n    font: small Helvetica Neue, sans-serif, Droid Sans Fallback;\n    background: var(--dfnpanel-bg);\n    color: var(--dfnpanel-text);\n    border: outset 0.2em;\n    white-space: normal; /* in case it's moved into a pre */\n}\n.dfn-panel:not(.on) { display: none; }\n.dfn-panel * { margin: 0; padding: 0; text-indent: 0; }\n.dfn-panel > b { display: block; }\n.dfn-panel a { color: var(--dfnpanel-text); }\n.dfn-panel a:not(:hover) { text-decoration: none !important; border-bottom: none !important; }\n.dfn-panel > b + b { margin-top: 0.25em; }\n.dfn-panel ul { padding: 0 0 0 1em; list-style: none; }\n.dfn-panel li a {\n    white-space: pre;\n    display: inline-block;\n    max-width: calc(300px - 1.5em - 1em);\n    overflow: hidden;\n    text-overflow: ellipsis;\n}\n\n.dfn-panel.activated {\n    display: inline-block;\n    position: fixed;\n    left: .5em;\n    bottom: 2em;\n    margin: 0 auto;\n    max-width: calc(100vw - 1.5em - .4em - .5em);\n    max-height: 30vh;\n}\n\n.dfn-paneled[role=\"button\"] { cursor: pointer; }\n</style>\n<style>/* Boilerplate: style-dfn-panel */\n:root {\n    --dfnpanel-bg: #ddd;\n    --dfnpanel-text: var(--text);\n}\n@media (prefers-color-scheme: dark) {\n    :root {\n        --dfnpanel-bg: #222;\n        --dfnpanel-text: var(--text);\n    }\n}\n.dfn-panel {\n    position: absolute;\n    z-index: 35;\n    width: 20em;\n    width: 300px;\n    height: auto;\n    max-height: 500px;\n    overflow: auto;\n    padding: 0.5em 0.75em;\n    font: small Helvetica Neue, sans-serif, Droid Sans Fallback;\n    background: var(--dfnpanel-bg);\n    color: var(--dfnpanel-text);\n    border: outset 0.2em;\n    white-space: normal; /* in case it's moved into a pre */\n}\n.dfn-panel:not(.on) { display: none; }\n.dfn-panel * { margin: 0; padding: 0; text-indent: 0; }\n.dfn-panel > b { display: block; }\n.dfn-panel a { color: var(--dfnpanel-text); }\n.dfn-panel a:not(:hover) { text-decoration: none !important; border-bottom: none !important; }\n.dfn-panel > b + b { margin-top: 0.25em; }\n.dfn-panel ul { padding: 0 0 0 1em; list-style: none; }\n.dfn-panel li a {\n    white-space: pre;\n    display: inline-block;\n    max-width: calc(300px - 1.5em - 1em);\n    overflow: hidden;\n    text-overflow: ellipsis;\n}\n\n.dfn-panel.activated {\n    display: inline-block;\n    position: fixed;\n    left: .5em;\n    bottom: 2em;\n    margin: 0 auto;\n    max-width: calc(100vw - 1.5em - .4em - .5em);\n    max-height: 30vh;\n}\n\n.dfn-paneled[role=\"button\"] { cursor: pointer; }\n</style>\n<style>/* Boilerplate: style-issues */\na[href].issue-return {\n    float: right;\n    float: inline-end;\n    color: var(--issueheading-text);\n    font-weight: bold;\n    text-decoration: none;\n}\n</style>\n<style>/* Boilerplate: style-md-lists */\n/* This is a weird hack for me not yet following the commonmark spec\n   regarding paragraph and lists. */\n[data-md] > :first-child {\n    margin-top: 0;\n}\n[data-md] > :last-child {\n    margin-bottom: 0;\n}\n</style>\n<style>/* Boilerplate: style-selflinks */\n\n:root {\n    --selflink-text: white;\n    --selflink-bg: gray;\n    --selflink-hover-text: black;\n}\n.heading, .issue, .note, .example, li, dt {\n    position: relative;\n}\na.self-link {\n    position: absolute;\n    top: 0;\n    left: calc(-1 * (3.5rem - 26px));\n    width: calc(3.5rem - 26px);\n    height: 2em;\n    text-align: center;\n    border: none;\n    transition: opacity .2s;\n    opacity: .5;\n}\na.self-link:hover {\n    opacity: 1;\n}\n.heading > a.self-link {\n    font-size: 83%;\n}\n.example > a.self-link,\n.note > a.self-link,\n.issue > a.self-link {\n    /* These blocks are overflow:auto, so positioning outside\n       doesn't work. */\n    left: auto;\n    right: 0;\n}\nli > a.self-link {\n    left: calc(-1 * (3.5rem - 26px) - 2em);\n}\ndfn > a.self-link {\n    top: auto;\n    left: auto;\n    opacity: 0;\n    width: 1.5em;\n    height: 1.5em;\n    background: var(--selflink-bg);\n    color: var(--selflink-text);\n    font-style: normal;\n    transition: opacity .2s, background-color .2s, color .2s;\n}\ndfn:hover > a.self-link {\n    opacity: 1;\n}\ndfn > a.self-link:hover {\n    color: var(--selflink-hover-text);\n}\n\na.self-link::before            { content: \"¶\"; }\n.heading > a.self-link::before { content: \"§\"; }\ndfn > a.self-link::before      { content: \"#\"; }\n</style>\n<style>/* Boilerplate: style-syntax-highlighting */\n\n            pre.idl.highlight {\n                background: var(--borderedblock-bg, var(--def-bg));\n            }\n            \n</style>\n<style>/* Boilerplate: style-syntax-highlighting */\n\ncode.highlight { padding: .1em; border-radius: .3em; }\npre.highlight, pre > code.highlight { display: block; padding: 1em; margin: .5em 0; overflow: auto; border-radius: 0; }\n\n.highlight:not(.idl) { background: rgba(0, 0, 0, .03); }\nc-[a] { color: #990055 } /* Keyword.Declaration */\nc-[b] { color: #990055 } /* Keyword.Type */\nc-[c] { color: #708090 } /* Comment */\nc-[d] { color: #708090 } /* Comment.Multiline */\nc-[e] { color: #0077aa } /* Name.Attribute */\nc-[f] { color: #669900 } /* Name.Tag */\nc-[g] { color: #222222 } /* Name.Variable */\nc-[k] { color: #990055 } /* Keyword */\nc-[l] { color: #000000 } /* Literal */\nc-[m] { color: #000000 } /* Literal.Number */\nc-[n] { color: #0077aa } /* Name */\nc-[o] { color: #999999 } /* Operator */\nc-[p] { color: #999999 } /* Punctuation */\nc-[s] { color: #a67f59 } /* Literal.String */\nc-[t] { color: #a67f59 } /* Literal.String.Single */\nc-[u] { color: #a67f59 } /* Literal.String.Double */\nc-[cp] { color: #708090 } /* Comment.Preproc */\nc-[c1] { color: #708090 } /* Comment.Single */\nc-[cs] { color: #708090 } /* Comment.Special */\nc-[kc] { color: #990055 } /* Keyword.Constant */\nc-[kn] { color: #990055 } /* Keyword.Namespace */\nc-[kp] { color: #990055 } /* Keyword.Pseudo */\nc-[kr] { color: #990055 } /* Keyword.Reserved */\nc-[ld] { color: #000000 } /* Literal.Date */\nc-[nc] { color: #0077aa } /* Name.Class */\nc-[no] { color: #0077aa } /* Name.Constant */\nc-[nd] { color: #0077aa } /* Name.Decorator */\nc-[ni] { color: #0077aa } /* Name.Entity */\nc-[ne] { color: #0077aa } /* Name.Exception */\nc-[nf] { color: #0077aa } /* Name.Function */\nc-[nl] { color: #0077aa } /* Name.Label */\nc-[nn] { color: #0077aa } /* Name.Namespace */\nc-[py] { color: #0077aa } /* Name.Property */\nc-[ow] { color: #999999 } /* Operator.Word */\nc-[mb] { color: #000000 } /* Literal.Number.Bin */\nc-[mf] { color: #000000 } /* Literal.Number.Float */\nc-[mh] { color: #000000 } /* Literal.Number.Hex */\nc-[mi] { color: #000000 } /* Literal.Number.Integer */\nc-[mo] { color: #000000 } /* Literal.Number.Oct */\nc-[sb] { color: #a67f59 } /* Literal.String.Backtick */\nc-[sc] { color: #a67f59 } /* Literal.String.Char */\nc-[sd] { color: #a67f59 } /* Literal.String.Doc */\nc-[se] { color: #a67f59 } /* Literal.String.Escape */\nc-[sh] { color: #a67f59 } /* Literal.String.Heredoc */\nc-[si] { color: #a67f59 } /* Literal.String.Interpol */\nc-[sx] { color: #a67f59 } /* Literal.String.Other */\nc-[sr] { color: #a67f59 } /* Literal.String.Regex */\nc-[ss] { color: #a67f59 } /* Literal.String.Symbol */\nc-[vc] { color: #0077aa } /* Name.Variable.Class */\nc-[vg] { color: #0077aa } /* Name.Variable.Global */\nc-[vi] { color: #0077aa } /* Name.Variable.Instance */\nc-[il] { color: #000000 } /* Literal.Number.Integer.Long */\n\n\n@media (prefers-color-scheme: dark) {\n    .highlight:not(.idl) { background: rgba(255, 255, 255, .05); }\n\n    c-[a] { color: #d33682 } /* Keyword.Declaration */\n    c-[b] { color: #d33682 } /* Keyword.Type */\n    c-[c] { color: #2aa198 } /* Comment */\n    c-[d] { color: #2aa198 } /* Comment.Multiline */\n    c-[e] { color: #268bd2 } /* Name.Attribute */\n    c-[f] { color: #b58900 } /* Name.Tag */\n    c-[g] { color: #cb4b16 } /* Name.Variable */\n    c-[k] { color: #d33682 } /* Keyword */\n    c-[l] { color: #657b83 } /* Literal */\n    c-[m] { color: #657b83 } /* Literal.Number */\n    c-[n] { color: #268bd2 } /* Name */\n    c-[o] { color: #657b83 } /* Operator */\n    c-[p] { color: #657b83 } /* Punctuation */\n    c-[s] { color: #6c71c4 } /* Literal.String */\n    c-[t] { color: #6c71c4 } /* Literal.String.Single */\n    c-[u] { color: #6c71c4 } /* Literal.String.Double */\n    c-[ch] { color: #2aa198 } /* Comment.Hashbang */\n    c-[cp] { color: #2aa198 } /* Comment.Preproc */\n    c-[cpf] { color: #2aa198 } /* Comment.PreprocFile */\n    c-[c1] { color: #2aa198 } /* Comment.Single */\n    c-[cs] { color: #2aa198 } /* Comment.Special */\n    c-[kc] { color: #d33682 } /* Keyword.Constant */\n    c-[kn] { color: #d33682 } /* Keyword.Namespace */\n    c-[kp] { color: #d33682 } /* Keyword.Pseudo */\n    c-[kr] { color: #d33682 } /* Keyword.Reserved */\n    c-[ld] { color: #657b83 } /* Literal.Date */\n    c-[nc] { color: #268bd2 } /* Name.Class */\n    c-[no] { color: #268bd2 } /* Name.Constant */\n    c-[nd] { color: #268bd2 } /* Name.Decorator */\n    c-[ni] { color: #268bd2 } /* Name.Entity */\n    c-[ne] { color: #268bd2 } /* Name.Exception */\n    c-[nf] { color: #268bd2 } /* Name.Function */\n    c-[nl] { color: #268bd2 } /* Name.Label */\n    c-[nn] { color: #268bd2 } /* Name.Namespace */\n    c-[py] { color: #268bd2 } /* Name.Property */\n    c-[ow] { color: #657b83 } /* Operator.Word */\n    c-[mb] { color: #657b83 } /* Literal.Number.Bin */\n    c-[mf] { color: #657b83 } /* Literal.Number.Float */\n    c-[mh] { color: #657b83 } /* Literal.Number.Hex */\n    c-[mi] { color: #657b83 } /* Literal.Number.Integer */\n    c-[mo] { color: #657b83 } /* Literal.Number.Oct */\n    c-[sa] { color: #6c71c4 } /* Literal.String.Affix */\n    c-[sb] { color: #6c71c4 } /* Literal.String.Backtick */\n    c-[sc] { color: #6c71c4 } /* Literal.String.Char */\n    c-[dl] { color: #6c71c4 } /* Literal.String.Delimiter */\n    c-[sd] { color: #6c71c4 } /* Literal.String.Doc */\n    c-[se] { color: #6c71c4 } /* Literal.String.Escape */\n    c-[sh] { color: #6c71c4 } /* Literal.String.Heredoc */\n    c-[si] { color: #6c71c4 } /* Literal.String.Interpol */\n    c-[sx] { color: #6c71c4 } /* Literal.String.Other */\n    c-[sr] { color: #6c71c4 } /* Literal.String.Regex */\n    c-[ss] { color: #6c71c4 } /* Literal.String.Symbol */\n    c-[fm] { color: #268bd2 } /* Name.Function.Magic */\n    c-[vc] { color: #cb4b16 } /* Name.Variable.Class */\n    c-[vg] { color: #cb4b16 } /* Name.Variable.Global */\n    c-[vi] { color: #cb4b16 } /* Name.Variable.Instance */\n    c-[vm] { color: #cb4b16 } /* Name.Variable.Magic */\n    c-[il] { color: #657b83 } /* Literal.Number.Integer.Long */\n}\n</style>\n<style>/* Boilerplate: style-var-click-highlighting */\n/*\nColors were chosen in Lab using https://nixsensor.com/free-color-converter/\nD50 2deg illuminant, L in [0,100], a and b in [-128, 128]\n0 = lab(85,0,85)\n1 = lab(85,80,30)\n2 = lab(85,-40,40)\n3 = lab(85,-50,0)\n4 = lab(85,5,15)\n5 = lab(85,-10,-50)\n6 = lab(85,35,-15)\n*/\nvar { cursor: pointer; }\nvar.selected0 { background-color: #F4D200; box-shadow: 0 0 0 2px #F4D200; }\nvar.selected1 { background-color: #FF87A2; box-shadow: 0 0 0 2px #FF87A2; }\nvar.selected2 { background-color: #96E885; box-shadow: 0 0 0 2px #96E885; }\nvar.selected3 { background-color: #3EEED2; box-shadow: 0 0 0 2px #3EEED2; }\nvar.selected4 { background-color: #EACFB6; box-shadow: 0 0 0 2px #EACFB6; }\nvar.selected5 { background-color: #82DDFF; box-shadow: 0 0 0 2px #82DDFF; }\nvar.selected6 { background-color: #FFBCF2; box-shadow: 0 0 0 2px #FFBCF2; }\n</style>\n<style>/* Boilerplate: style-wpt */\n:root {\n    --wpt-border: hsl(0, 0%, 60%);\n    --wpt-bg: hsl(0, 0%, 95%);\n    --wpt-text: var(--text);\n    --wptheading-text: hsl(0, 0%, 30%);\n}\n@media (prefers-color-scheme: dark) {\n    :root {\n        --wpt-border: hsl(0, 0%, 30%);\n        --wpt-bg: var(--borderedblock-bg);\n        --wpt-text: var(--text);\n        --wptheading-text: hsl(0, 0%, 60%);\n    }\n}\n.wpt-tests-block {\n    list-style: none;\n    border-left: .5em solid var(--wpt-border);\n    background: var(--wpt-bg);\n    color: var(--wpt-text);\n    margin: 1em auto;\n    padding: .5em;\n}\n.wpt-tests-block summary {\n    color: var(--wptheading-text);\n    font-weight: normal;\n    text-transform: uppercase;\n}\n.wpt-tests-block summary::marker{\n    color: var(--wpt-border);\n}\n.wpt-tests-block summary:hover::marker{\n    color: var(--wpt-text);\n}\n/*\n   The only content  of a wpt test block in its closed state is the <summary>,\n   which contains the word TESTS,\n   and that is absolutely positioned.\n   In that closed state, wpt test blocks are styled\n   to have a top margin whose height is exactly equal\n   to the height of the absolutely positioned <summary>,\n   and no other background/padding/margin/border.\n   The wpt test block elements will therefore allow the maring\n   of the previous/next block elements\n   to collapse through them;\n   if this combined margin would be larger than its own top margin,\n   it stays as is,\n   and therefore the pre-existing vertical rhythm of the document is undisturbed.\n   If that combined margin would be smaller, it is grown to that size.\n   This means that the wpt test block ensures\n   that there's always enough vertical space to insert the summary,\n   without adding more than is needed.\n*/\n.wpt-tests-block:not([open]){\n    padding: 0;\n    border: none;\n    background: none;\n    font-size: 0.75em;\n    line-height: 1;\n    position: relative;\n    margin: 1em 0 0;\n}\n.wpt-tests-block:not([open]) summary {\n    position: absolute;\n    right: 0;\n    bottom: 0;\n}\n/*\n   It is possible that both the last child of a block element\n   and the block element itself\n   would be annotated with a <wpt> block each.\n   If the block element has a padding or a border,\n   that's fine, but otherwise\n   the bottom margin of the block and of its last child would collapse\n   and both <wpt> elements would overlap, being both placed there.\n   To avoid that, add 1px of padding to the <wpt> element annotating the last child\n   to prevent the bottom margin of the block and of its last child from collapsing\n   (and as much negative margin,\n   as wel only want to prevent margin collapsing,\n   but are not trying to actually take more space).\n*/\n.wpt-tests-block:not([open]):last-child {\n    padding-bottom: 1px;\n    margin-bottom: -1px;\n}\n/*\n   Exception to the previous rule:\n   don't do that in non-last list items,\n   because it's not necessary,\n   and would therefore consume more space than strictly needed.\n   Lists must have list items as children, not <wpt> elements,\n   so a <wpt> element cannot be a sibling of a list item,\n   and the collision that the previous rule avoids cannot happen.\n*/\nli:not(:last-child) > .wpt-tests-block:not([open]):last-child,\ndd:not(:last-child) > .wpt-tests-block:not([open]):last-child {\n    padding-bottom: 0;\n    margin-bottom: 0;\n}\n.wpt-tests-block:not([open]):not(:hover){\n    opacity: 0.5;\n}\n.wpt-tests-list {\n    list-style: none;\n    display: grid;\n    margin: 0;\n    padding: 0;\n    grid-template-columns: 1fr max-content auto auto;\n    grid-column-gap: .5em;\n}\n.wpt-tests-block hr:last-child {\n    display: none;\n}\n.wpt-test {\n    display: contents;\n}\n.wpt-test > a {\n    text-decoration: underline;\n    border: none;\n}\n.wpt-test > .wpt-name { grid-column: 1; }\n.wpt-test > .wpt-results { grid-column: 2; }\n.wpt-test > .wpt-live { grid-column: 3; }\n.wpt-test > .wpt-source { grid-column: 4; }\n\n.wpt-test > .wpt-results {\n    display: flex;\n    gap: .1em;\n}\n.wpt-test .wpt-result {\n    display: inline-block;\n    height: 1em;\n    width: 1em;\n    border-radius: 50%;\n    position: relative;\n}\n</style>\n <body class=\"h-entry\">\n  <div class=\"head\">\n   <p data-fill-with=\"logo\"><a class=\"logo\" href=\"https://www.w3.org/\"> <img alt=\"W3C\" height=\"48\" src=\"https://www.w3.org/StyleSheets/TR/2021/logos/W3C\" width=\"72\"> </a> </p>\n   <h1 class=\"p-name no-ref\" id=\"title\">URL Fragment Text Directives</h1>\n   <p id=\"w3c-state\"><a href=\"https://www.w3.org/standards/types#CG-DRAFT\">Draft Community Group Report</a>, <time class=\"dt-updated\" datetime=\"2023-12-13\">13 December 2023</time></p>\n   <div data-fill-with=\"spec-metadata\">\n    <dl>\n     <dt>This version:\n     <dd><a class=\"u-url\" href=\"https://wicg.github.io/scroll-to-text-fragment/\">https://wicg.github.io/scroll-to-text-fragment/</a>\n     <dt>Issue Tracking:\n     <dd><a href=\"https://github.com/wicg/scroll-to-text-fragment/issues/\">GitHub</a>\n     <dd><a href=\"#issues-index\">Inline In Spec</a>\n     <dt class=\"editor\">Editors:\n     <dd class=\"editor p-author h-card vcard\"><a class=\"p-name fn u-email email\" href=\"mailto:nburris@chromium.org\">Nick Burris</a> (<a class=\"p-org org\" href=\"https://www.google.com\">Google</a>)\n     <dd class=\"editor p-author h-card vcard\"><a class=\"p-name fn u-email email\" href=\"mailto:bokan@chromium.org\">David Bokan</a> (<a class=\"p-org org\" href=\"https://www.google.com\">Google</a>)\n     <dt>Test Suite:\n     <dd class=\"wpt-overview\"><a href=\"https://wpt.fyi/results/scroll-to-text-fragment/\">https://wpt.fyi/results/scroll-to-text-fragment/</a>\n    </dl>\n   </div>\n   <div data-fill-with=\"warning\"></div>\n   <p class=\"copyright\" data-fill-with=\"copyright\"><a href=\"https://www.w3.org/policies/#copyright\">Copyright</a> © 2023 the Contributors to the URL Fragment Text Directives Specification, published by the <a href=\"https://www.w3.org/community/wicg/\">Web Platform Incubator Community Group</a> under the <a href=\"https://www.w3.org/community/about/agreements/cla/\">W3C Community Contributor License Agreement (CLA)</a>.\nA human-readable <a href=\"http://www.w3.org/community/about/agreements/cla-deed/\">summary</a> is available. </p>\n   <hr title=\"Separator for header\">\n  </div>\n  <div class=\"p-summary\" data-fill-with=\"abstract\">\n   <h2 class=\"no-num no-toc no-ref heading settled\" id=\"abstract\"><span class=\"content\">Abstract</span></h2>\n   <p>Text directives add support for specifying a text snippet in the URL\n\n    fragment. When navigating to a URL with such a fragment, the user agent\n    can quickly emphasise and/or bring it to the user’s attention.</p>\n  </div>\n  <div data-fill-with=\"at-risk\"></div>\n  <h2 class=\"no-num no-toc no-ref heading settled\" id=\"status\"><span class=\"content\">Status of this document</span></h2>\n  <div data-fill-with=\"status\">\n   <p> This specification was published by the <a href=\"https://www.w3.org/community/wicg/\">Web Platform Incubator Community Group</a>.\n  It is not a W3C Standard nor is it on the W3C Standards Track.\n\n  Please note that under the <a href=\"https://www.w3.org/community/about/agreements/cla/\">W3C Community Contributor License Agreement (CLA)</a> there is a limited opt-out and other conditions apply.\n\n  Learn more about <a href=\"http://www.w3.org/community/\">W3C Community and Business Groups</a>. </p>\n   <p></p>\n  </div>\n  <div data-fill-with=\"at-risk\"></div>\n  <nav data-fill-with=\"table-of-contents\" id=\"toc\">\n   <h2 class=\"no-num no-toc no-ref\" id=\"contents\">Table of Contents</h2>\n   <ol class=\"toc\" role=\"directory\">\n    <li><a href=\"#infrastructure\"><span class=\"secno\">1</span> <span class=\"content\">Infrastructure</span></a>\n    <li>\n     <a href=\"#introduction\"><span class=\"secno\">2</span> <span class=\"content\">Introduction</span></a>\n     <ol class=\"toc\">\n      <li>\n       <a href=\"#use-cases\"><span class=\"secno\">2.1</span> <span class=\"content\">Use cases</span></a>\n       <ol class=\"toc\">\n        <li><a href=\"#web-text-references\"><span class=\"secno\">2.1.1</span> <span class=\"content\">Web text references</span></a>\n        <li><a href=\"#user-sharing\"><span class=\"secno\">2.1.2</span> <span class=\"content\">User sharing</span></a>\n       </ol>\n      <li><a href=\"#link-lifetime\"><span class=\"secno\">2.2</span> <span class=\"content\">Link Lifetime</span></a>\n     </ol>\n    <li>\n     <a href=\"#description\"><span class=\"secno\">3</span> <span class=\"content\">Description</span></a>\n     <ol class=\"toc\">\n      <li><a href=\"#indication\"><span class=\"secno\">3.1</span> <span class=\"content\">Indication</span></a>\n      <li>\n       <a href=\"#syntax\"><span class=\"secno\">3.2</span> <span class=\"content\">Syntax</span></a>\n       <ol class=\"toc\">\n        <li><a href=\"#context-terms\"><span class=\"secno\">3.2.1</span> <span class=\"content\">Context Terms</span></a>\n        <li><a href=\"#bidi-considerations\"><span class=\"secno\">3.2.2</span> <span class=\"content\">BiDi Considerations</span></a>\n       </ol>\n      <li>\n       <a href=\"#the-fragment-directive\"><span class=\"secno\">3.3</span> <span class=\"content\">The Fragment Directive</span></a>\n       <ol class=\"toc\">\n        <li><a href=\"#extracting-the-fragment-directive\"><span class=\"secno\">3.3.1</span> <span class=\"content\">Extracting the fragment directive</span></a>\n        <li><a href=\"#applying-directives-to-a-document\"><span class=\"secno\">3.3.2</span> <span class=\"content\">Applying directives to a document</span></a>\n        <li><a href=\"#fragment-directive-grammar\"><span class=\"secno\">3.3.3</span> <span class=\"content\">Fragment directive grammar</span></a>\n       </ol>\n      <li>\n       <a href=\"#text-directives\"><span class=\"secno\">3.4</span> <span class=\"content\">Text Directives</span></a>\n       <ol class=\"toc\">\n        <li><a href=\"#invoking-text-directives\"><span class=\"secno\">3.4.1</span> <span class=\"content\">Invoking Text Directives</span></a>\n       </ol>\n      <li>\n       <a href=\"#security-and-privacy\"><span class=\"secno\">3.5</span> <span class=\"content\">Security and Privacy</span></a>\n       <ol class=\"toc\">\n        <li><a href=\"#motivation\"><span class=\"secno\">3.5.1</span> <span class=\"content\">Motivation</span></a>\n        <li><a href=\"#scroll-on-navigation\"><span class=\"secno\">3.5.2</span> <span class=\"content\">Scroll On Navigation</span></a>\n        <li><a href=\"#search-timing\"><span class=\"secno\">3.5.3</span> <span class=\"content\">Search Timing</span></a>\n        <li><a href=\"#restricting-the-text-fragment\"><span class=\"secno\">3.5.4</span> <span class=\"content\">Restricting the Text Fragment</span></a>\n        <li><a href=\"#restricting-scroll-on-load\"><span class=\"secno\">3.5.5</span> <span class=\"content\">Restricting Scroll on Load</span></a>\n       </ol>\n      <li>\n       <a href=\"#navigating-to-text-fragment\"><span class=\"secno\">3.6</span> <span class=\"content\">Navigating to a Text Fragment</span></a>\n       <ol class=\"toc\">\n        <li><a href=\"#finding-ranges-in-a-document\"><span class=\"secno\">3.6.1</span> <span class=\"content\">Finding Ranges in a Document</span></a>\n        <li><a href=\"#word-boundaries\"><span class=\"secno\">3.6.2</span> <span class=\"content\">Word Boundaries</span></a>\n       </ol>\n      <li>\n       <a href=\"#indicating-the-text-match\"><span class=\"secno\">3.7</span> <span class=\"content\">Indicating The Text Match</span></a>\n       <ol class=\"toc\">\n        <li>\n         <a href=\"#urls-in-ua-features\"><span class=\"secno\">3.7.1</span> <span class=\"content\">URLs in UA features</span></a>\n         <ol class=\"toc\">\n          <li><a href=\"#urls-in-location-bar\"><span class=\"secno\">3.7.1.1</span> <span class=\"content\">Location Bar</span></a>\n          <li><a href=\"#urls-in-bookmarks\"><span class=\"secno\">3.7.1.2</span> <span class=\"content\">Bookmarks</span></a>\n          <li><a href=\"#urls-in-sharing\"><span class=\"secno\">3.7.1.3</span> <span class=\"content\">Sharing</span></a>\n         </ol>\n       </ol>\n      <li><a href=\"#document-policy-integration\"><span class=\"secno\">3.8</span> <span class=\"content\">Document Policy Integration</span></a>\n      <li><a href=\"#feature-detectability\"><span class=\"secno\">3.9</span> <span class=\"content\">Feature Detectability</span></a>\n     </ol>\n    <li>\n     <a href=\"#generating-text-fragment-directives\"><span class=\"secno\">4</span> <span class=\"content\">Generating Text Fragment Directives</span></a>\n     <ol class=\"toc\">\n      <li><a href=\"#prefer-exact-matching-to-range-based\"><span class=\"secno\">4.1</span> <span class=\"content\">Prefer Exact Matching To Range-based</span></a>\n      <li><a href=\"#use-context-only-when-necessary\"><span class=\"secno\">4.2</span> <span class=\"content\">Use Context Only When Necessary</span></a>\n      <li><a href=\"#determine-if-fragment-id-is-needed\"><span class=\"secno\">4.3</span> <span class=\"content\">Determine If Fragment Id Is Needed</span></a>\n     </ol>\n    <li>\n     <a href=\"#w3c-conformance\"><span class=\"secno\"></span> <span class=\"content\">Conformance</span></a>\n     <ol class=\"toc\">\n      <li><a href=\"#w3c-conventions\"><span class=\"secno\"></span> <span class=\"content\">Document conventions</span></a>\n     </ol>\n    <li>\n     <a href=\"#index\"><span class=\"secno\"></span> <span class=\"content\">Index</span></a>\n     <ol class=\"toc\">\n      <li><a href=\"#index-defined-here\"><span class=\"secno\"></span> <span class=\"content\">Terms defined by this specification</span></a>\n      <li><a href=\"#index-defined-elsewhere\"><span class=\"secno\"></span> <span class=\"content\">Terms defined by reference</span></a>\n     </ol>\n    <li>\n     <a href=\"#references\"><span class=\"secno\"></span> <span class=\"content\">References</span></a>\n     <ol class=\"toc\">\n      <li><a href=\"#normative\"><span class=\"secno\"></span> <span class=\"content\">Normative References</span></a>\n      <li><a href=\"#informative\"><span class=\"secno\"></span> <span class=\"content\">Informative References</span></a>\n     </ol>\n    <li><a href=\"#idl-index\"><span class=\"secno\"></span> <span class=\"content\">IDL Index</span></a>\n    <li><a href=\"#issues-index\"><span class=\"secno\"></span> <span class=\"content\">Issues Index</span></a>\n   </ol>\n  </nav>\n  <main>\n   <h2 class=\"heading settled\" data-level=\"1\" id=\"infrastructure\"><span class=\"secno\">1. </span><span class=\"content\">Infrastructure</span><a class=\"self-link\" href=\"#infrastructure\"></a></h2>\n   <p>This specification depends on the Infra Standard. <a data-link-type=\"biblio\" href=\"#biblio-infra\" title=\"Infra Standard\">[INFRA]</a> </p>\n   <h2 class=\"heading settled\" data-level=\"2\" id=\"introduction\"><span class=\"secno\">2. </span><span class=\"content\">Introduction</span><a class=\"self-link\" href=\"#introduction\"></a></h2>\n   <div class=\"note\" role=\"note\">This section is non-normative</div>\n   <h3 class=\"heading settled\" data-level=\"2.1\" id=\"use-cases\"><span class=\"secno\">2.1. </span><span class=\"content\">Use cases</span><a class=\"self-link\" href=\"#use-cases\"></a></h3>\n   <h4 class=\"heading settled\" data-level=\"2.1.1\" id=\"web-text-references\"><span class=\"secno\">2.1.1. </span><span class=\"content\">Web text references</span><a class=\"self-link\" href=\"#web-text-references\"></a></h4>\n    The core use case for text fragments is to allow URLs to serve as an exact text\nreference across the web. For example, Wikipedia references could link to the\nexact text they are quoting from a page. Similarly, search engines can serve\nURLs that direct the user to the answer they are looking for in the page rather\nthan linking to the top of the page. \n   <h4 class=\"heading settled\" data-level=\"2.1.2\" id=\"user-sharing\"><span class=\"secno\">2.1.2. </span><span class=\"content\">User sharing</span><a class=\"self-link\" href=\"#user-sharing\"></a></h4>\n    With text directives, browsers may implement an option to 'Copy URL to here'\nwhen the user opens the context menu on a text selection. The browser can then\ngenerate a URL with the text selection appropriately specified, and the\nrecipient of the URL will have the specified text conveniently indicated.\nWithout text fragments, if a user wants to share a passage of text from a page,\nthey would likely just copy and paste the passage, in which case the receiver\nloses the context of the page. \n   <h3 class=\"heading settled\" data-level=\"2.2\" id=\"link-lifetime\"><span class=\"secno\">2.2. </span><span class=\"content\">Link Lifetime</span><a class=\"self-link\" href=\"#link-lifetime\"></a></h3>\n   <p>This specification attempts to maximize the useful lifetime of text directive links, for example, by\nusing the actual text content as the URL payload, and allowing a fallback element-id fragment.\nHowever, pages on the web often update and change their content. As such, links like this may \"rot\"\nin that the text content they point to no longer exists on the destination page.</p>\n   <p>Text directive links can be useful despite this problem. In user sharing use cases, the link is\noften transient, intended to be used only within a short time of sending. For longer duration use\ncases, such as references and web page links, text directives are still valuable since they degrade\ngracefully into an ordinary link. Additionally, the presence of a stale text directive can be useful\ninformation to surface to a user, to help them understand the link creator’s original intent and\nthat the page content may have changed since the link was created.</p>\n   <p>See <a href=\"#generating-text-fragment-directives\">§ 4 Generating Text Fragment Directives</a> for best practices on how to create robust text\ndirective links.</p>\n   <h2 class=\"heading settled\" data-level=\"3\" id=\"description\"><span class=\"secno\">3. </span><span class=\"content\">Description</span><a class=\"self-link\" href=\"#description\"></a></h2>\n   <h3 class=\"heading settled\" data-level=\"3.1\" id=\"indication\"><span class=\"secno\">3.1. </span><span class=\"content\">Indication</span><a class=\"self-link\" href=\"#indication\"></a></h3>\n   <div class=\"note\" role=\"note\">This section is non-normative</div>\n   <p>This specification intentionally doesn’t define what actions a user agent takes\nto \"indicate\" a text match. There are different experiences and trade-offs a\nuser agent could make. Some examples of possible actions:</p>\n   <ul>\n    <li data-md>\n     <p>Providing visual emphasis or highlight of the text passage</p>\n    <li data-md>\n     <p>Automatically scrolling the passage into view when the page is navigated</p>\n    <li data-md>\n     <p>Activating a UA’s find-in-page feature on the text passage</p>\n    <li data-md>\n     <p>Providing a \"Click to scroll to text passage\" notification</p>\n    <li data-md>\n     <p>Providing a notification when the text passage isn’t found in the page</p>\n   </ul>\n   <div class=\"note\" role=\"note\"> The choice of action can have implications for user security and privacy.  See\nthe <a href=\"#security-and-privacy\">§ 3.5 Security and Privacy</a> section for details. </div>\n   <h3 class=\"heading settled\" data-level=\"3.2\" id=\"syntax\"><span class=\"secno\">3.2. </span><span class=\"content\">Syntax</span><a class=\"self-link\" href=\"#syntax\"></a></h3>\n   <div class=\"note\" role=\"note\">This section is non-normative</div>\n   <p>A <a data-link-type=\"dfn\" href=\"#text-directive\" id=\"ref-for-text-directive\">text directive</a> is specified in the <a data-link-type=\"dfn\" href=\"#fragment-directive\" id=\"ref-for-fragment-directive\">fragment directive</a> (see <a href=\"#the-fragment-directive\">§ 3.3 The Fragment Directive</a>) with the following format:</p>\n<pre>#:~:text=[prefix-,]start[,end][,-suffix]\n          context  |--match--|  context\n</pre>\n   <p><em>(Square brackets indicate an optional parameter)</em></p>\n   <p>The text parameters are percent-decoded before matching. Dash (-), ampersand\n(&amp;), and comma (,) characters in text parameters are percent-encoded to avoid\nbeing interpreted as part of the text directive syntax.</p>\n   <p>The only required parameter is <code>start</code>. If only <code>start</code> is specified, the\nfirst instance of this exact text string is the target text.</p>\n   <div class=\"example\" id=\"example-4e85550d\"><a class=\"self-link\" href=\"#example-4e85550d\"></a> <code>#:~:text=an%20example%20text%20fragment</code> indicates that the\nexact text \"an example text fragment\" is the target text. </div>\n   <p>If the <code>end</code> parameter is also specified, then the text directive refers to a\nrange of text in the page. The target text range is the text range starting at\nthe first instance of <code>start</code>, until the first instance of <code>end</code> that\nappears after <code>start</code>. This is equivalent to specifying the entire text range\nin the <code>start</code> parameter, but allows the URL to avoid being bloated with a\nlong text directive.</p>\n   <div class=\"example\" id=\"example-7df2027e\"><a class=\"self-link\" href=\"#example-7df2027e\"></a> <code>#:~:text=an%20example,text%20fragment</code> indicates that the first\ninstance of \"an example\" until the following first instance of \"text fragment\"\nis the target text. </div>\n   <h4 class=\"heading settled\" data-level=\"3.2.1\" id=\"context-terms\"><span class=\"secno\">3.2.1. </span><span class=\"content\">Context Terms</span><a class=\"self-link\" href=\"#context-terms\"></a></h4>\n   <div class=\"note\" role=\"note\">This section is non-normative</div>\n   <p>The other two optional parameters are context terms. They are specified by the\ndash (-) character succeeding the prefix and preceding the suffix, to\ndifferentiate them from the <code>start</code> and <code>end</code> parameters, as any\ncombination of optional parameters can be specified.</p>\n   <p>Context terms are used to disambiguate the target text fragment. The context\nterms can specify the text immediately before (prefix) and immediately after\n(suffix) the text fragment, allowing for whitespace.</p>\n   <div class=\"note\" role=\"note\"> While a match succeeds only if the context terms surround the target text\nfragment, any amount of whitespace is allowed between context terms and the text\nfragment. This allows context terms to cross element boundaries, for example if\nthe target text fragment is at the beginning of a paragraph and needs\ndisambiguation by the previous element’s text as a prefix. </div>\n   <p>The context terms are not part of the targeted text fragment and are not\nvisually indicated.</p>\n   <div class=\"example\" id=\"example-5c87b699\"><a class=\"self-link\" href=\"#example-5c87b699\"></a> <code>#:~:text=this%20is-,an%20example,-text%20fragment</code> would match\nto \"an example\" in \"this is an example text fragment\", but not match to \"an\nexample\" in \"here is an example text\". </div>\n   <h4 class=\"heading settled\" data-level=\"3.2.2\" id=\"bidi-considerations\"><span class=\"secno\">3.2.2. </span><span class=\"content\">BiDi Considerations</span><a class=\"self-link\" href=\"#bidi-considerations\"></a></h4>\n   <div class=\"note\" role=\"note\">This section is non-normative</div>\n   <div class=\"note\" role=\"note\"> See <a href=\"https://www.w3.org/International/articles/inline-bidi-markup/uba-basics.en\">Unicode\n  Bidirectional Algorithm basics</a> for a good overview of how Bidirectional\n  text works. </div>\n   <p>Since URL strings are ASCII encoded, they provide no built-in support for\nbi-directional text. However, the content that we wish to target on a page can\nbe LTR (left-to-right), RTL (right-to-left) or both (Bidirectional/BiDi). This\nsection provides an intuitive description the behavior implicitly described by\nthe normative sections further in this spec.</p>\n   <p>The characters of each term in the text fragment are in <em>logical order</em>,\nthat is, the order in which a native reader would read them in (and also the\norder in which characters are stored in memory).</p>\n   <p>Similarly, the <code>prefix</code> and <code>start</code> terms identify\ntext coming before another term in logical order, while <code>suffix</code> and <code>end</code> follow other terms in logical order.</p>\n   <p class=\"note\" role=\"note\"><span class=\"marker\">Note:</span> user agents can visually render URLs in a manner friendlier to a native\nreader, for example, by converting the displayed string to Unicode. However, the\nstring representation of a URL remains plain ASCII characters.</p>\n   <div class=\"example\" id=\"example-b17c0d6b\">\n    <a class=\"self-link\" href=\"#example-b17c0d6b\"></a> Suppose we want to select the text <code lang=\"ar\">مِصر‎</code> (Egypt, in Arabic),\n  that’s preceeded by <code lang=\"ar\">البحرين‎</code> (Bahrain, in Arabic). We would\n  first percent encode each term: \n    <p><code lang=\"ar\">مِصر‎</code> becomes \"%D9%85%D8%B5%D8%B1\" (Note: UTF-8 character\n  [0xD9,0x85] is the first (right-most) character of the Arabic word.)</p>\n    <p><code lang=\"ar\">البحرين‎</code> becomes \"%D8%A7%D9%84%D8%A8%D8%AD%D8%B1%D9%8A%D9%86\"</p>\n    <p>The text fragment would then become:</p>\n    <p><code> :~:text=%D8%A7%D9%84%D8%A8%D8%AD%D8%B1%D9%8A%D9%86-,%D9%85%D8%B5%D8%B1 </code></p>\n    <p>When displayed in a browser’s address bar, the browser can visually render the\n  text in its natural RTL direction, appearing to the user:</p>\n    <p><code> :~:text=<span lang=\"ar\">البحرين</span>-,<span lang=\"ar\">مِصر</span> </code></p>\n   </div>\n   <h3 class=\"heading settled\" data-level=\"3.3\" id=\"the-fragment-directive\"><span class=\"secno\">3.3. </span><span class=\"content\">The Fragment Directive</span><a class=\"self-link\" href=\"#the-fragment-directive\"></a></h3>\n   <p>To avoid compatibility issues with usage of existing URL fragments, this spec\nintroduces the concept of a <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"fragment-directive\">fragment directive</dfn>. It is the portion of\nthe URL <a data-link-type=\"dfn\" href=\"https://url.spec.whatwg.org/#concept-url-fragment\" id=\"ref-for-concept-url-fragment\">fragment</a> that follows the <a data-link-type=\"dfn\" href=\"#fragment-directive-delimiter\" id=\"ref-for-fragment-directive-delimiter\">fragment directive delimiter</a> and\nmay be null if the delimiter does not appear in the fragment.</p>\n   <p>The <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"fragment-directive-delimiter\">fragment directive delimiter</dfn> is the string \":~:\", that is the\nthree consecutive code points U+003A (:), U+007E (~), U+003A (:).</p>\n   <div class=\"note\" role=\"note\"> The <a data-link-type=\"dfn\" href=\"#fragment-directive\" id=\"ref-for-fragment-directive①\">fragment directive</a> is part of the URL fragment. This means it\n  always appears after a U+0023 (#) code point in a URL. </div>\n   <div class=\"example\" id=\"example-6998d91f\"><a class=\"self-link\" href=\"#example-6998d91f\"></a> To add a <a data-link-type=\"dfn\" href=\"#fragment-directive\" id=\"ref-for-fragment-directive②\">fragment directive</a> to a URL like https://example.com, a fragment\n  is first appended to the URL: https://example.com#:~:text=foo. </div>\n   <p>The fragment directive is parsed and processed into individual <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"directives\">directives</dfn>, which are instructions to the user agent to perform some\naction. Multiple directives may appear in the fragment directive.</p>\n   <div class=\"note\" role=\"note\"> The only directive introduced in this spec is the text directive but others\n  could be added in the future. </div>\n   <div class=\"example\" id=\"example-9acce0ff\">\n    <a class=\"self-link\" href=\"#example-9acce0ff\"></a> <code>https://example.com#:~:text=foo&amp;text=bar&amp;unknownDirective</code> \n    <p>Contains 2 text directives and one unknown directive.</p>\n   </div>\n   <p>To prevent impacting page operation, it is stripped from script-accessible APIs to prevent\ninteraction with author script. This also ensures future directives can be added without web\ncompatibility risk.</p>\n   <h4 class=\"heading settled\" data-level=\"3.3.1\" id=\"extracting-the-fragment-directive\"><span class=\"secno\">3.3.1. </span><span class=\"content\">Extracting the fragment directive</span><a class=\"self-link\" href=\"#extracting-the-fragment-directive\"></a></h4>\n   <p>This section describes the mechanism by which the fragment directive is hidden\nfrom script and how it fits into <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigation-and-session-history\"><cite>HTML</cite> § 7.4 Navigation and session history</a>.</p>\n   <div class=\"note\" role=\"note\">\n     The summarized changes in this section: \n    <ul>\n     <li data-md>\n      <p>Session history entries now include a new \"directive state\" item</p>\n     <li data-md>\n      <p>All new entries are created with a directive state with an empty value. If the new URL includes\n  a fragment directive it will be written to the state’s value (otherwise it remains null).</p>\n     <li data-md>\n      <p>Any time a URL potentially including a fragment directive is written to a session history entry,\n  extract the fragment directive from the URL and store it in a directive state item of the\n  entry. There are four such points where a URL can potentially include a directive:</p>\n      <ul>\n       <li data-md>\n        <p>In the \"navigate\" steps for typical cross-document navigations</p>\n       <li data-md>\n        <p>In the \"navigate to a fragment\" steps for fragment based same-document navigations</p>\n       <li data-md>\n        <p>In the \"URL and history update steps\" for synchronous updates such as\n  pushState/replaceState.</p>\n       <li data-md>\n        <p>In the \"create navigation params by fetching\" steps for URLs coming from a redirect.</p>\n      </ul>\n     <li data-md>\n      <p>Same-document navigations that change only the fragment, and the new URL doesn’t specify a\n  directive, will create an entry whose directive state refers to the previous entry’s directive\n  state.</p>\n    </ul>\n   </div>\n   <p>In <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#session-history-infrastructure\"><cite>HTML</cite> § 7.4.1 Session history</a>, define <a data-link-type=\"dfn\" href=\"#directive-state\" id=\"ref-for-directive-state\">directive state</a>:</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#session-history-infrastructure\"><cite>HTML</cite> § 7.4.1 Session history</a>:</strong></p>\n    <p><dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"directive-state\">directive state</dfn> holds the value of the <a data-link-type=\"dfn\" href=\"#fragment-directive\" id=\"ref-for-fragment-directive③\">fragment directive</a> at the time the session\n  history entry was created and is used to invoke directives, such as text highlighting, whenever\n  the entry is traversed. It has:</p>\n    <ul>\n     <li data-md>\n      <p><dfn class=\"dfn-paneled\" data-dfn-for=\"directive state\" data-dfn-type=\"dfn\" data-noexport id=\"directive-state-value\">value</dfn>, the <a data-link-type=\"dfn\" href=\"#fragment-directive\" id=\"ref-for-fragment-directive④\">fragment directive</a> <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#ascii-string\" id=\"ref-for-ascii-string\">ASCII string</a> or null,\n  initially null.</p>\n    </ul>\n    <p>A <a data-link-type=\"dfn\" href=\"#directive-state\" id=\"ref-for-directive-state①\">directive state</a> may be shared by multiple session history entries.</p>\n    <div class=\"note\" role=\"note\">\n     <p>The fragment directive is removed from the URL before the URL is set to the session\n      history entry. It is instead stored in the directive state. This prevents it from being\n      visible to script APIs so that a directive can be specified without interfering with a\n      page’s operation.</p>\n     <p>The fragment directive is stored in the directive state object, rather than a raw string,\n      since the same directive state can be shared across multiple contiguous session history\n      entries. On a traversal, the directive is only processed (i.e. search text and highlight) if\n      the directive state has changed between two entries.</p>\n    </div>\n   </blockquote>\n   <p>To the definition of <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#session-history-entry\">session history entry</a>, add:</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#session-history-entries\"><cite>HTML</cite> § 7.4.1.1 Session history entries</a>:</strong></p>\n    <div class=\"monkeypatch\">\n     A session history entry is a struct with the following items: \n     <ul>\n      <li data-md>\n       <p>...</p>\n      <li data-md>\n       <p>persisted user state, which is implementation-defined, initially null</p>\n      <li data-md>\n       <p><span class=\"diff\"><dfn class=\"dfn-paneled\" data-dfn-for=\"she\" data-dfn-type=\"dfn\" data-noexport id=\"she-directive-state\">directive state</dfn>, a <a data-link-type=\"dfn\" href=\"#directive-state\" id=\"ref-for-directive-state②\">directive state</a>,\ninitially a new <a data-link-type=\"dfn\" href=\"#directive-state\" id=\"ref-for-directive-state③\">directive state</a></span></p>\n     </ul>\n    </div>\n   </blockquote>\n   <p>Add a helper algorithm for removing and returning a fragment directive string from a <a data-link-type=\"dfn\" href=\"https://url.spec.whatwg.org/#concept-url\" id=\"ref-for-concept-url\">URL</a>:</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a data-link-type=\"biblio\" href=\"#biblio-html\" title=\"HTML Standard\">[HTML]</a>:</strong></p>\n    <div class=\"note\" role=\"note\"> This algorithm makes a URL’s fragment end at the <a data-link-type=\"dfn\" href=\"#fragment-directive-delimiter\" id=\"ref-for-fragment-directive-delimiter①\">fragment directive\n    delimiter</a>. The returned <a data-link-type=\"dfn\" href=\"#fragment-directive\" id=\"ref-for-fragment-directive⑤\">fragment directive</a> includes all characters that follow the\n    delimiter but does not include the delimiter. </div>\n    <div class=\"issue\" id=\"issue-f4a5d96b\"><a class=\"self-link\" href=\"#issue-f4a5d96b\"></a> TODO: If a URL’s fragment ends with ':~:' (i.e. empty directive), this will return null which\n    is treated as the URL not specifying an explicit directive (and avoids clobbering an existing\n    one. But maybe in this case we should return the empty string? That way a page can explicitly\n    clear directives/highlights by navigating/pushState to '#:~:'. </div>\n    <p>To <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"remove-the-fragment-directive\">remove the fragment directive</dfn> from a <a data-link-type=\"dfn\" href=\"https://url.spec.whatwg.org/#concept-url\" id=\"ref-for-concept-url①\">URL</a> <var>url</var>, run these steps:</p>\n    <ol>\n     <li data-md>\n      <p>Let <var>raw fragment</var> be equal to <var>url</var>’s <a data-link-type=\"dfn\" href=\"https://url.spec.whatwg.org/#concept-url-fragment\" id=\"ref-for-concept-url-fragment①\">fragment</a>.</p>\n     <li data-md>\n      <p>Let <var>fragment directive</var> be null.</p>\n     <li data-md>\n      <p>If <var>raw fragment</var> is non-null and contains the <a data-link-type=\"dfn\" href=\"#fragment-directive-delimiter\" id=\"ref-for-fragment-directive-delimiter②\">fragment directive delimiter</a> as a\n  substring:</p>\n      <ol>\n       <li data-md>\n        <p>Let <var>position</var> be the <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#string-position-variable\" id=\"ref-for-string-position-variable\">position variable</a> pointing to the first code\n  point of the first instance, if one exists, of the <a data-link-type=\"dfn\" href=\"#fragment-directive-delimiter\" id=\"ref-for-fragment-directive-delimiter③\">fragment directive delimiter</a> in <var>raw fragment</var>, or past the end of <var>raw fragment</var> otherwise.</p>\n       <li data-md>\n        <p>Let <var>new fragment</var> be the <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#code-point-substring-by-positions\" id=\"ref-for-code-point-substring-by-positions\">code point substring by positions</a> of <var>raw fragment</var> from\n  the start of <var>raw fragment</var> to <var>position</var>.</p>\n       <li data-md>\n        <p>Advance <var>position</var> by the <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#string-code-point-length\" id=\"ref-for-string-code-point-length\">code point length</a> of the <a data-link-type=\"dfn\" href=\"#fragment-directive-delimiter\" id=\"ref-for-fragment-directive-delimiter④\">fragment directive\n  delimiter</a>.</p>\n       <li data-md>\n        <p>If <var>position</var> does not point past the end of <var>raw fragment</var>:</p>\n        <ol>\n         <li data-md>\n          <p>Set <var>fragment directive</var> to the <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#code-point-substring-to-the-end-of-the-string\" id=\"ref-for-code-point-substring-to-the-end-of-the-string\">code point substring to the end of the string</a> <var>raw fragment</var> starting from <var>position</var></p>\n        </ol>\n       <li data-md>\n        <p>Set <var>url</var>’s <a data-link-type=\"dfn\" href=\"https://url.spec.whatwg.org/#concept-url-fragment\" id=\"ref-for-concept-url-fragment②\">fragment</a> to <var>new fragment</var>.</p>\n      </ol>\n     <li data-md>\n      <p>Return <var>fragment directive</var>.</p>\n    </ol>\n    <div class=\"example\" id=\"example-775c8cc2\"><a class=\"self-link\" href=\"#example-775c8cc2\"></a> <code>https://example.org/#test:~:text=foo</code> will be parsed such that\n     the fragment is the string \"test\" and the <a data-link-type=\"dfn\" href=\"#fragment-directive\" id=\"ref-for-fragment-directive⑥\">fragment directive</a> is the string\n     \"text=foo\". </div>\n   </blockquote>\n   <p>The next four monkeypatches modify the creation of a session history entry, where the URL might\ncontain a fragment directive, to remove the fragment directive and store it in the <a data-link-type=\"dfn\" href=\"#directive-state\" id=\"ref-for-directive-state④\">directive\nstate</a>.</p>\n   <p>In the definition of <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate\" id=\"ref-for-navigate\">navigate</a>:</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#beginning-navigation\"><cite>HTML</cite> § 7.4.2.2 Beginning navigation</a>:</strong></p>\n    <div class=\"monkeypatch\">\n     To navigate a navigable navigable to a URL <var>url</var>...: \n     <ol>\n      <li data-md>\n       <p>...</p>\n      <li value=\"14\">Set navigable’s ongoing navigation to navigationId.\n      <li data-md>\n       <p>If url’s scheme is \"javascript\", then...</p>\n      <li data-md>\n       <p>In parallel, run these steps:</p>\n       <ol>\n        <li data-md>\n         <p>...</p>\n        <li value=\"5\">If url is about:blank, then set documentState’s origin to documentState’s initiator origin.\n        <li data-md>\n         <p>Otherwise, if url is about:srcdoc, then set documentState’s origin to navigable’s parent’s active document’s origin.</p>\n        <li data-md>\n         <strike>Let historyEntry be a new session history entry, with its URL set to url and\nits document state set to documentState.</strike>\n        <li value=\"7\"><span class=\"diff\">Let <var>fragment directive</var> be the result of running <a data-link-type=\"dfn\" href=\"#remove-the-fragment-directive\" id=\"ref-for-remove-the-fragment-directive\">remove the\nfragment directive</a> on <var>url</var>.</span>\n        <li data-md>\n         <p><span class=\"diff\">Let <var>directive state</var> be a new <a data-link-type=\"dfn\" href=\"#directive-state\" id=\"ref-for-directive-state⑤\">directive\nstate</a> with <a data-link-type=\"dfn\" href=\"#directive-state-value\" id=\"ref-for-directive-state-value\">value</a> set to <var>fragment directive</var>.</span></p>\n        <li data-md>\n         <p><span class=\"diff\">Let historyEntry be a new session history entry, with its URL\nset to <var>url</var>, its document state set to documentState, and its <a data-link-type=\"dfn\" href=\"#she-directive-state\" id=\"ref-for-she-directive-state\">directive state</a> set to <var>directive state</var>.</span></p>\n        <li data-md>\n         <p>Let navigationParams be null.</p>\n        <li data-md>\n         <p>...</p>\n       </ol>\n     </ol>\n    </div>\n   </blockquote>\n   <p>In the definition of <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate-fragid\" id=\"319d7c290\">navigate to a fragment</a>:</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#scroll-to-fragid\"><cite>HTML</cite> § 7.4.2.3.3 Fragment navigations</a>:</strong></p>\n    <div class=\"monkeypatch\">\n     To navigate to a fragment given navigable <var>navigable</var>, ...: \n     <ol>\n      <li data-md>\n       <p><span class=\"diff\">Let <var>directive state</var> be navigable’s active session history\nentry’s <a data-link-type=\"dfn\" href=\"#she-directive-state\" id=\"ref-for-she-directive-state①\">directive state</a>.</span></p>\n      <li data-md>\n       <p><span class=\"diff\">Let <var>fragment directive</var> be the result of running <a data-link-type=\"dfn\" href=\"#remove-the-fragment-directive\" id=\"ref-for-remove-the-fragment-directive①\">remove the fragment directive</a> on <var>url</var>.</span></p>\n      <li data-md>\n       <p><span class=\"diff\">If <var>fragment directive</var> is not null:</span></p>\n       <div class=\"note\" role=\"note\">Otherwise, when only the fragment has changed and it did not specify\na directive, the active entry’s directive state is reused. This prevents a fragment\nchange from clobbering highlights.</div>\n       <ol>\n        <li data-md>\n         <p><span class=\"diff\">Let <var>directive state</var> be a new <a data-link-type=\"dfn\" href=\"#directive-state\" id=\"ref-for-directive-state⑥\">directive state</a> with <a data-link-type=\"dfn\" href=\"#directive-state-value\" id=\"ref-for-directive-state-value①\">value</a> set to <var>fragment directive</var>.</span></p>\n       </ol>\n      <li data-md>\n       <p>Let historyEntry be a new session history entry, with</p>\n       <ul>\n        <li data-md>\n         <p>URL url</p>\n        <li data-md>\n         <p>document state navigable’s active session history entry’s document state</p>\n        <li data-md>\n         <p>scroll restoration mode navigable’s active session history entry’s scroll restoration\nmode</p>\n        <li data-md>\n         <p><span class=\"diff\"><a data-link-type=\"dfn\" href=\"#she-directive-state\" id=\"ref-for-she-directive-state②\">directive state</a> <var>directive state</var></span></p>\n       </ul>\n      <li data-md>\n       <p>Let entryToReplace be navigable’s active session history entry if historyHandling is\n\"replace\", otherwise null.</p>\n      <li data-md>\n       <p>...</p>\n     </ol>\n    </div>\n   </blockquote>\n   <p>In the definition of <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#url-and-history-update-steps\">URL and history update steps</a>:</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate-non-frag-sync\"><cite>HTML</cite> § 7.4.4 Non-fragment synchronous \"navigations\"</a>:</strong></p>\n    <div class=\"monkeypatch\">\n     The URL and history update steps, given a Document <var>document</var>, ...: \n     <ol>\n      <li data-md>\n       <p>Let <var>navigable</var> be <var>document</var>’s node navigable.</p>\n      <li data-md>\n       <p>Let <var>activeEntry</var> be <var>navigable</var>’s active session history entry.</p>\n      <li data-md>\n       <p><span class=\"diff\">Let <var>fragment directive</var> be the result of running <a data-link-type=\"dfn\" href=\"#remove-the-fragment-directive\" id=\"ref-for-remove-the-fragment-directive②\">remove the\nfragment directive</a> on <var>newUrl</var>.</span></p>\n      <li data-md>\n       <p>Let <var>historyEntry</var> be a new session history entry, with</p>\n       <ul>\n        <li data-md>\n         <p>URL <var>newUrl</var></p>\n        <li data-md>\n         <p>...</p>\n        <li data-md>\n         <p><span class=\"diff\"><a data-link-type=\"dfn\" href=\"#she-directive-state\" id=\"ref-for-she-directive-state③\">directive state</a> <var>activeEntry</var>’s <a data-link-type=\"dfn\" href=\"#she-directive-state\" id=\"ref-for-she-directive-state④\">directive\nstate</a></span></p>\n       </ul>\n      <li data-md>\n       <p>If <var>document</var>’s is initial about:blank is true, then set historyHandling to \"replace\".</p>\n      <li data-md>\n       <p>If historyHandling is \"push\", then:</p>\n       <ol>\n        <li data-md>\n         <p>Increment document’s history object’s index.</p>\n        <li data-md>\n         <p>Set document’s history object’s length to its index + 1.</p>\n        <li data-md>\n         <p><span class=\"diff\">If <var>newUrl</var> does not equal <var>activeEntry</var>’s URL with exclude\nfragments set to true OR <var>fragment directive</var> is not null, then:</span></p>\n         <div class=\"note\" role=\"note\">Otherwise, when only the fragment has changed and it did not specify\na directive, the active entry’s directive state is reused. This prevents a fragment\nchange from clobbering highlights.</div>\n         <ol>\n          <li data-md>\n           <p><span class=\"diff\">Let <var>historyEntry</var>’s <a data-link-type=\"dfn\" href=\"#she-directive-state\" id=\"ref-for-she-directive-state⑤\">directive state</a> be a new <a data-link-type=\"dfn\" href=\"#directive-state\" id=\"ref-for-directive-state⑦\">directive state</a> with <a data-link-type=\"dfn\" href=\"#directive-state-value\" id=\"ref-for-directive-state-value②\">value</a> set to <var>fragment\ndirective</var>.</span></p>\n         </ol>\n       </ol>\n      <li data-md>\n       <p><span class=\"diff\">Otherwise, if <var>fragment directive</var> is not null, set <var>historyEntry</var>’s <a data-link-type=\"dfn\" href=\"#she-directive-state\" id=\"ref-for-she-directive-state⑥\">directive state</a>'s <a data-link-type=\"dfn\" href=\"#directive-state-value\" id=\"ref-for-directive-state-value③\">value</a> to <var>fragment\ndirective</var>.</span></p>\n      <li data-md>\n       <p>If serializedData is not null, then restore the history object state given document and\nnewEntry.</p>\n     </ol>\n    </div>\n   </blockquote>\n   <p>In the definition of <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#create-navigation-params-by-fetching\" id=\"fc0e1ad00\"> create navigation params by fetching</a>:</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#populating-a-session-history-entry\"><cite>HTML</cite> § 7.4.5 Populating a session history entry</a>:</strong></p>\n    <div class=\"monkeypatch\">\n     To create navigation params by fetching given a session history entry <var>entry</var>, ...: \n     <ol>\n      <li data-md>\n       <p class=\"assertion\">Assert: this is running in parallel.</p>\n      <li data-md>\n       <p>...</p>\n      <li value=\"17\">Let currentURL be request’s current URL.\n      <li data-md>\n       <p>Let commitEarlyHints be null.</p>\n      <li data-md>\n       <p>While true:</p>\n       <ol>\n        <li data-md>\n         <p>If request’s reserved client is not null and currentURL’s origin is not the same as request’s reserved client’s creation URL’s origin, then:</p>\n        <li data-md>\n         <p>...</p>\n        <li value=\"21\">Set currentURL to <var>locationURL</var>.\n        <li data-md>\n         <p><span class=\"diff\">Let <var>fragment directive</var> be the result of running <a data-link-type=\"dfn\" href=\"#remove-the-fragment-directive\" id=\"ref-for-remove-the-fragment-directive③\">remove the fragment directive</a> on <var>locationURL</var>.</span></p>\n        <li data-md>\n         <strike class=\"diff\">Set <var>entry</var>’s URL to currentURL.</strike>\n        <li data-md>\n         <p><span class=\"diff\">Set <var>entry</var>’s URL to <var>locationURL</var>.</span></p>\n        <li data-md>\n         <p><span class=\"diff\">Set <var>entry</var>’s <a data-link-type=\"dfn\" href=\"#she-directive-state\" id=\"ref-for-she-directive-state⑦\">directive state</a>'s <a data-link-type=\"dfn\" href=\"#directive-state-value\" id=\"ref-for-directive-state-value④\">value</a> to <var>fragment directive</var>.</span></p>\n        <li data-md>\n         <p>If <var>locationURL</var> is a URL whose scheme is not a fetch scheme, then return a new non-fetch\nscheme navigation params, with initiator origin request’s current URL’s origin</p>\n        <li data-md>\n         <p>...</p>\n       </ol>\n     </ol>\n    </div>\n   </blockquote>\n   <div class=\"note\" role=\"note\">\n    <p> Since a Document is populated from a history entry, its <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-document-url\" id=\"ref-for-concept-document-url\">URL</a> will not include the\n    fragment directive. Similarly, since a window’s <code class=\"idl\"><a data-link-type=\"idl\" href=\"https://html.spec.whatwg.org/multipage/nav-history-apis.html#location\" id=\"ref-for-location\">Location</a></code> object is a representation of the <a data-link-type=\"dfn\" href=\"https://url.spec.whatwg.org/#concept-url\" id=\"ref-for-concept-url②\">URL</a> of the <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/document-sequences.html#nav-document\" id=\"ref-for-nav-document\">active document</a>, all getters on it will show a fragment-directive-stripped\n    version of the URL. </p>\n    <p> Additionally, since the <code class=\"idl\"><a data-link-type=\"idl\" href=\"https://html.spec.whatwg.org/multipage/nav-history-apis.html#hashchangeevent\" id=\"ref-for-hashchangeevent\">HashChangeEvent</a></code> is <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#updating-the-document\"> fired in response to a changed fragment</a> between URLs of session history entries, <code>hashchange</code> will not be fired if a navigation or traversal changes only the fragment\n    directive. </p>\n    <p> Some examples are provided to help clarify various edge cases. </p>\n   </div>\n   <div class=\"example\" id=\"example-c4fd5b50\">\n    <a class=\"self-link\" href=\"#example-c4fd5b50\"></a> \n<pre>window.location = \"https://example.com#page1:~:hello\";\nconsole.log(window.location.href); // 'https://example.com#page1'\nconsole.log(window.location.hash); // '#page1'\n</pre>\n    <p>The initial navigation created a new session history entry. The entry’s URL is stripped of the\n  fragment directive: \"https://example.com#page1\". The entry’s directive state value is set to\n  \"hello\". Since the document is populated from the entry, web APIs don’t include the fragment\n  directive in URLs.</p>\n<pre>location.hash = \"page2\";\nconsole.log(location.href); // 'https://example.com#page2'\n</pre>\n    <p>A same document navigation changed only the fragment. This adds a new session history entry in the <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate-fragid\" id=\"319d7c291\">navigate to\n  a fragment</a> steps. However, since only the fragment changed, the new entry’s directive state\n  points to the same state as the first entry, with a value of \"bar\".</p>\n<pre>onhashchange = () => console.assert(false, \"hashchange doesn’t fire.\");\nlocation.hash = \"page2:~:world\";\nconsole.log(location.href); // 'https://example.com#page2'\nonhashchange = null;\n</pre>\n    <p>A same document navigation changes only the fragment but includes a fragment directive. Since an\n  explicit directive was provided, the new entry includes its own directive state with a value of\n  \"fizz\".</p>\n    <p>The hashchange event is not fired since the page-visible fragment is unchanged; only the fragment\n  directive changed. This is because the comparison for hashchange is done on the URLs in the\n  session history entries, where the fragment directive has been removed.</p>\n<pre>history.pushState(\"\", \"\", \"page3\");\nconsole.log(location.href); // 'https://example.com/page3'\n</pre>\n    <p>pushState creates a new session history entry for the same document. However, since the\n  non-fragment URL has changed, this entry has its own directive state with value currently null.</p>\n   </div>\n   <div class=\"example\" id=\"example-f4d8b076\">\n    <a class=\"self-link\" href=\"#example-f4d8b076\"></a> In other cases where a URL is not set to a session history entry, there is no\n  fragment directive stripping. \n    <p>For URL objects:</p>\n<pre>let url = new URL('https://example.com#foo:~:bar');\nconsole.log(url.href); // 'https://example.com#foo:~:bar'\nconsole.log(url.hash); // '#foo:~:bar'\n\ndocument.url = url;\nconsole.log(document.url.href); // 'https://example.com#foo:~:bar'\nconsole.log(document.url.hash); // '#foo:~:bar'\n\n</pre>\n    <p>The <code>&lt;a></code> or <code>&lt;area></code> elements:</p>\n<pre>&lt;a id='anchor' href=\"https://example.com#foo:~:bar\">Anchor&lt;/a>\n&lt;script>\n  console.log(anchor.href); // 'https://example.com#foo:~:bar'\n  console.log(anchor.hash); // '#foo:~:bar'\n&lt;/script>\n</pre>\n   </div>\n   <h4 class=\"heading settled\" data-level=\"3.3.2\" id=\"applying-directives-to-a-document\"><span class=\"secno\">3.3.2. </span><span class=\"content\">Applying directives to a document</span><a class=\"self-link\" href=\"#applying-directives-to-a-document\"></a></h4>\n   <p>The section above described how the <a data-link-type=\"dfn\" href=\"#fragment-directive\" id=\"ref-for-fragment-directive⑦\">fragment directive</a> is separated from the URL and stored in a\nsession history entry.</p>\n   <p>This section defines how and when navigations and traversals make use of history entry’s <a data-link-type=\"dfn\" href=\"#she-directive-state\" id=\"ref-for-she-directive-state⑧\">directive\nstate</a> to apply the directives associated with a session history entry to a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-document\" id=\"ref-for-concept-document\">Document</a>.</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a href=\"https://dom.spec.whatwg.org/#interface-document\"><cite>DOM</cite> § 4.5 Interface Document</a>:</strong></p>\n    <p>Each document has an associated <dfn class=\"dfn-paneled\" data-dfn-for=\"Document\" data-dfn-type=\"dfn\" data-noexport id=\"document-pending-text-directives\">pending text directives</dfn> which is either\n  null or an <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#list\" id=\"ref-for-list\">list</a> of <a data-link-type=\"dfn\" href=\"#text-directive\" id=\"ref-for-text-directive①\">text directives</a>. It is initially null.</p>\n   </blockquote>\n   <p>In the definition of <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#update-document-for-history-step-application\" id=\"ref-for-update-document-for-history-step-application\">update document for history step application</a>:</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#updating-the-document\"><cite>HTML</cite> § 7.4.6.2 Updating the document</a>:</strong></p>\n    <div class=\"monkeypatch\">\n     To update document for history step application given a Document <var>document</var>, a session history entry <var>entry</var>,... \n     <ol>\n      <li data-md>\n       <p>...</p>\n      <li value=\"4\">Set <var>document</var>’s history object’s length to scriptHistoryLength\n      <li data-md>\n       <p>If <var>documentsEntryChanged</var> is true, then:</p>\n       <ol>\n        <li data-md>\n         <p>Let <var>oldURL</var> be <var>document</var>’s latest entry’s URL.</p>\n        <li data-md>\n         <div class=\"diff\">\n          If <var>document</var>’s latest entry’s <a data-link-type=\"dfn\" href=\"#she-directive-state\" id=\"ref-for-she-directive-state⑨\">directive state</a> is not <var>entry</var>’s <a data-link-type=\"dfn\" href=\"#she-directive-state\" id=\"ref-for-she-directive-state①⓪\">directive state</a> then: \n          <ol>\n           <li data-md>\n            <p>Let <var>fragment directive</var> be <var>entry</var>’s <a data-link-type=\"dfn\" href=\"#she-directive-state\" id=\"ref-for-she-directive-state①①\">directive state</a>'s <a data-link-type=\"dfn\" href=\"#directive-state-value\" id=\"ref-for-directive-state-value⑤\">value</a>.</p>\n           <li data-md>\n            <p>Set <var>document</var>’s <a data-link-type=\"dfn\" href=\"#document-pending-text-directives\" id=\"ref-for-document-pending-text-directives\">pending text directives</a> to the result of <a data-link-type=\"dfn\" href=\"#parse-the-fragment-directive\" id=\"ref-for-parse-the-fragment-directive\">parsing</a> <var>fragment directive</var>.</p>\n          </ol>\n         </div>\n       </ol>\n      <li data-md>\n       <p>Set <var>document</var>’s latest entry to <var>entry</var></p>\n      <li data-md>\n       <p>...</p>\n     </ol>\n    </div>\n   </blockquote>\n   <h4 class=\"heading settled\" data-level=\"3.3.3\" id=\"fragment-directive-grammar\"><span class=\"secno\">3.3.3. </span><span class=\"content\">Fragment directive grammar</span><a class=\"self-link\" href=\"#fragment-directive-grammar\"></a></h4>\n   <p class=\"note\" role=\"note\"><span class=\"marker\">Note:</span> This section is non-normative.</p>\n   <p class=\"note\" role=\"note\"><span class=\"marker\">Note:</span> This grammar is provided as a convenient reference; however, the rules and steps for parsing\nare specified imperatively in the <a href=\"#text-directives\">§ 3.4 Text Directives</a> section. Where this grammar differs in\nbehavior from the steps of that section, the steps there are to be taken as the authoritative source\nof truth.</p>\n   <p>The <a data-link-type=\"dfn\" href=\"#fragmentdirectiveproduction\" id=\"ref-for-fragmentdirectiveproduction\">FragmentDirective</a> can contain multiple directives split by the \"&amp;\" character. Currently this\nmeans we allow multiple text directives to enable multiple indicated strings in the page, but this\nalso allows for future directive types to be added and combined. For extensibility, we do not fail\nto parse if an unknown directive is in the &amp;-separated list of directives.</p>\n   <p>A <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#string\" id=\"ref-for-string\">string</a> is a valid fragment directive if it matches the EBNF (Extended\nBackus-Naur Form) production:</p>\n   <dl>\n    <dt> <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"fragmentdirectiveproduction\"><code>FragmentDirective</code></dfn> <code>::=</code> \n    <dd> <code>(<a data-link-type=\"dfn\" href=\"#textdirective\" id=\"ref-for-textdirective\">TextDirective</a> | <a data-link-type=\"dfn\" href=\"#unknowndirective\" id=\"ref-for-unknowndirective\">UnknownDirective</a>) (\"&amp;\" <a data-link-type=\"dfn\" href=\"#fragmentdirectiveproduction\" id=\"ref-for-fragmentdirectiveproduction①\">FragmentDirective</a>)?</code> \n    <dt> <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"textdirective\"><code>TextDirective</code></dfn> <code>::=</code> \n    <dd> <code>\"text=\"<a data-link-type=\"dfn\" href=\"#characterstring\" id=\"ref-for-characterstring\">CharacterString</a></code> \n    <dt> <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"unknowndirective\"><code>UnknownDirective</code></dfn> <code>::=</code> \n    <dd> <code><a data-link-type=\"dfn\" href=\"#characterstring\" id=\"ref-for-characterstring①\">CharacterString</a> - <a data-link-type=\"dfn\" href=\"#textdirective\" id=\"ref-for-textdirective①\">TextDirective</a></code> \n    <dt> <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"characterstring\"><code>CharacterString</code></dfn> <code>::=</code> \n    <dd> <code>(<a data-link-type=\"dfn\" href=\"#explicitchar\" id=\"ref-for-explicitchar\">ExplicitChar</a> | <a data-link-type=\"dfn\" href=\"#percentencodedbyte\" id=\"ref-for-percentencodedbyte\">PercentEncodedByte</a>)*</code> \n    <dt> <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"explicitchar\"><code>ExplicitChar</code></dfn> <code>::=</code> \n    <dd>\n      <code>[a-zA-Z0-9] | \"!\" | \"$\" | \"'\" | \"(\" | \")\" | \"*\" | \"+\" | \".\" | \"/\" | \":\" |\n    \";\" | \"=\" | \"?\" | \"@\" | \"_\" | \"~\" | \",\" | \"-\"</code> \n     <div class=\"note\" role=\"note\"> An <a data-link-type=\"dfn\" href=\"#explicitchar\" id=\"ref-for-explicitchar①\">ExplicitChar</a> may be any <a data-link-type=\"dfn\" href=\"https://url.spec.whatwg.org/#url-code-points\" id=\"ref-for-url-code-points\">URL code point</a> other than \"&amp;\". </div>\n   </dl>\n   <p>A <a data-link-type=\"dfn\" href=\"#textdirective\" id=\"ref-for-textdirective②\">TextDirective</a> is considered valid if it matches the following production:</p>\n   <dl>\n    <dt><dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"validtextdirective\"><code>ValidTextDirective</code></dfn> <code>::=</code>\n    <dd><code>\"text=\" <a data-link-type=\"dfn\" href=\"#textdirectiveparameters\" id=\"ref-for-textdirectiveparameters\">TextDirectiveParameters</a></code>\n    <dt><dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"textdirectiveparameters\"><code>TextDirectiveParameters</code></dfn> <code>::=</code>\n    <dd> <code> (<a data-link-type=\"dfn\" href=\"#textdirectiveprefix\" id=\"ref-for-textdirectiveprefix\">TextDirectivePrefix</a> \",\")? <a data-link-type=\"dfn\" href=\"#textdirectivestring\" id=\"ref-for-textdirectivestring\">TextDirectiveString</a> (\",\" <a data-link-type=\"dfn\" href=\"#textdirectivestring\" id=\"ref-for-textdirectivestring①\">TextDirectiveString</a>)?  (\",\" <a data-link-type=\"dfn\" href=\"#textdirectivesuffix\" id=\"ref-for-textdirectivesuffix\">TextDirectiveSuffix</a>)? </code> \n    <dt><dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"textdirectiveprefix\"><code>TextDirectivePrefix</code></dfn> <code>::=</code>\n    <dd><code><a data-link-type=\"dfn\" href=\"#textdirectivestring\" id=\"ref-for-textdirectivestring②\">TextDirectiveString</a>\"-\"</code>\n    <dt><dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"textdirectivesuffix\"><code>TextDirectiveSuffix</code></dfn> <code>::=</code>\n    <dd><code>\"-\"<a data-link-type=\"dfn\" href=\"#textdirectivestring\" id=\"ref-for-textdirectivestring③\">TextDirectiveString</a></code>\n    <dt><dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"textdirectivestring\"><code>TextDirectiveString</code></dfn> <code>::=</code>\n    <dd><code>(<a data-link-type=\"dfn\" href=\"#textdirectiveexplicitchar\" id=\"ref-for-textdirectiveexplicitchar\">TextDirectiveExplicitChar</a> | <a data-link-type=\"dfn\" href=\"#percentencodedbyte\" id=\"ref-for-percentencodedbyte①\">PercentEncodedByte</a>)+</code>\n    <dt><dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"textdirectiveexplicitchar\"><code>TextDirectiveExplicitChar</code></dfn> <code>::=</code>\n    <dd>\n      <code> [a-zA-Z0-9] | \"!\" | \"$\" | \"'\" | \"(\" | \")\" | \"*\" | \"+\" | \".\" | \"/\" | \":\" |\n    \";\" | \"=\" | \"?\" | \"@\" | \"_\" | \"~\" </code> \n     <div class=\"note\" role=\"note\"> A <a data-link-type=\"dfn\" href=\"#textdirectiveexplicitchar\" id=\"ref-for-textdirectiveexplicitchar①\">TextDirectiveExplicitChar</a> is any <a data-link-type=\"dfn\" href=\"https://url.spec.whatwg.org/#url-code-points\" id=\"ref-for-url-code-points①\">URL code point</a> that is not explicitly used in the <a data-link-type=\"dfn\" href=\"#fragmentdirectiveproduction\" id=\"ref-for-fragmentdirectiveproduction②\">FragmentDirective</a> or <a data-link-type=\"dfn\" href=\"#validtextdirective\" id=\"ref-for-validtextdirective\">ValidTextDirective</a> syntax, that is \"&amp;\", \"-\", and \",\".  If a text\n    fragment refers to a \"&amp;\", \"-\", or \",\" character in the document, it will be percent-encoded in\n    the fragment. </div>\n    <dt><dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"percentencodedbyte\"><code>PercentEncodedByte</code></dfn> <code>::=</code>\n    <dd><code>\"%\" [a-zA-Z0-9][a-zA-Z0-9]</code>\n   </dl>\n   <h3 class=\"heading settled\" data-level=\"3.4\" id=\"text-directives\"><span class=\"secno\">3.4. </span><span class=\"content\">Text Directives</span><a class=\"self-link\" href=\"#text-directives\"></a></h3>\n   <p>A <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"text-directive\">text directive</dfn> is a kind of <a data-link-type=\"dfn\" href=\"#directives\" id=\"ref-for-directives\">directive</a> representing a range of\ntext to be indicated to the user. It is a <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#struct\" id=\"ref-for-struct\">struct</a> that consists of\nfour strings: <dfn class=\"dfn-paneled\" data-dfn-for=\"text directive\" data-dfn-type=\"dfn\" data-noexport id=\"text-directive-start\">start</dfn>, <dfn class=\"dfn-paneled\" data-dfn-for=\"text directive\" data-dfn-type=\"dfn\" data-noexport id=\"text-directive-end\">end</dfn>, <dfn class=\"dfn-paneled\" data-dfn-for=\"text directive\" data-dfn-type=\"dfn\" data-noexport id=\"text-directive-prefix\">prefix</dfn>, and <dfn class=\"dfn-paneled\" data-dfn-for=\"text directive\" data-dfn-type=\"dfn\" data-noexport id=\"text-directive-suffix\">suffix</dfn>. <a data-link-type=\"dfn\" href=\"#text-directive-start\" id=\"ref-for-text-directive-start\">start</a> is required to be non-null. The other three items may be set to null,\nindicating they weren’t provided. The empty string is not a valid value for any\nof these items.</p>\n   <p>See <a href=\"#syntax\">§ 3.2 Syntax</a> for the what each of these components means and how they’re\nused.</p>\n   <div class=\"algorithm\" data-algorithm=\"percent-decode a text directive term\">\n     To <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"percent-decode-a-text-directive-term\">percent-decode a text directive term</dfn> given an input <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#string\" id=\"ref-for-string①\">string</a> <var>term</var>: \n    <ol class=\"algorithm\">\n     <li data-md>\n      <p>If <var>term</var> is null, return null.</p>\n     <li data-md>\n      <p><a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#assert\" id=\"ref-for-assert\">Assert</a>: <var>term</var> is an <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#ascii-string\" id=\"ref-for-ascii-string①\">ASCII string</a>.</p>\n     <li data-md>\n      <p>Let <var>decoded bytes</var> be the result of <a data-link-type=\"dfn\" href=\"https://url.spec.whatwg.org/#string-percent-decode\" id=\"ref-for-string-percent-decode\">percent-decoding</a> <var>term</var>.</p>\n     <li data-md>\n      <p>Return the result of running <a data-link-type=\"dfn\" href=\"https://encoding.spec.whatwg.org/#utf-8-decode-without-bom\" id=\"ref-for-utf-8-decode-without-bom\">UTF-8 decode without BOM</a> on <var>decoded\nbytes</var>.</p>\n    </ol>\n   </div>\n   <div class=\"algorithm\" data-algorithm=\"parse a text directive\">\n     To <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"parse-a-text-directive\">parse a text directive</dfn>, on an <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#string\" id=\"ref-for-string②\">string</a> <var>text\n  directive value</var>, run these steps: \n    <div class=\"note\" role=\"note\">\n     <p> This algorithm takes a single text directive value string as input (e.g.  \"prefix-,foo,bar\") and\n      attempts to parse the string into the components of the directive (e.g. (\"prefix\", \"foo\", \"bar\",\n      null)). See <a href=\"#syntax\">§ 3.2 Syntax</a> for the what each of these components means and how they’re used. </p>\n     <p> Returns null if the input is invalid. Otherwise, returns a <a data-link-type=\"dfn\" href=\"#text-directive\" id=\"ref-for-text-directive②\">text directive</a>. </p>\n    </div>\n    <ol class=\"algorithm\">\n     <li data-md>\n      <p>Let <var>prefix</var>, <var>suffix</var>, <var>start</var>, <var>end</var>, each be null.</p>\n     <li data-md>\n      <p><a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#assert\" id=\"ref-for-assert①\">Assert</a>: <var>text directive value</var> is an <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#ascii-string\" id=\"ref-for-ascii-string②\">ASCII string</a> with no code points in the <a data-link-type=\"dfn\" href=\"https://url.spec.whatwg.org/#fragment-percent-encode-set\" id=\"ref-for-fragment-percent-encode-set\">fragment percent-encode set</a> and no instances of\nU+0026 (&amp;).</p>\n     <li data-md>\n      <p>Let <var>tokens</var> be a <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#list\" id=\"ref-for-list①\">list</a> of <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#string\" id=\"ref-for-string③\">strings</a> that result from <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#strictly-split\" id=\"ref-for-strictly-split\">strictly splitting</a> <var>text directive value</var> on U+002C (,).</p>\n     <li data-md>\n      <p>If <var>tokens</var> has <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#list-size\" id=\"ref-for-list-size\">size</a> less than 1 or greater than 4, return null.</p>\n     <li data-md>\n      <p>If the first item of <var>tokens</var> <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#string-ends-with\" id=\"ref-for-string-ends-with\">ends with</a> U+002D (-):</p>\n      <ol>\n       <li data-md>\n        <p>Set <var>prefix</var> to the <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#code-point-substring\" id=\"ref-for-code-point-substring\">substring</a> of <var>tokens</var>[0]\nfrom 0 with length <var>tokens</var>[0]'s <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#string-code-point-length\" id=\"ref-for-string-code-point-length①\">length</a> - 1.</p>\n       <li data-md>\n        <p>Remove the first item of <var>tokens</var>.</p>\n       <li data-md>\n        <p>If <var>prefix</var> is the empty string or contains any instances of U+002D (-), return null.</p>\n       <li data-md>\n        <p>If <var>tokens</var> is <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#list-empty\" id=\"ref-for-list-empty\">empty</a>, return null.</p>\n      </ol>\n     <li data-md>\n      <p>If the last item of <var>tokens</var> <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#string-starts-with\" id=\"ref-for-string-starts-with\">starts with</a> U+002D (-):</p>\n      <ol>\n       <li data-md>\n        <p>Set <var>suffix</var> to the <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#code-point-substring-to-the-end-of-the-string\" id=\"ref-for-code-point-substring-to-the-end-of-the-string①\">substring</a> of the last item of <var>tokens</var> from 1 to the end of the string.</p>\n       <li data-md>\n        <p>Remove the last item of <var>tokens</var>.</p>\n       <li data-md>\n        <p>If <var>suffix</var> is the empty string or contains any instances of U+002D (-), return null.</p>\n       <li data-md>\n        <p>If <var>tokens</var> is <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#list-empty\" id=\"ref-for-list-empty①\">empty</a>, return null.</p>\n      </ol>\n     <li data-md>\n      <p>If <var>tokens</var> has <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#list-size\" id=\"ref-for-list-size①\">size</a> greater than 2, return null.</p>\n     <li data-md>\n      <p><a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#assert\" id=\"ref-for-assert②\">Assert</a>: <var>tokens</var> has <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#list-size\" id=\"ref-for-list-size②\">size</a> 1 or 2.</p>\n     <li data-md>\n      <p>Set <var>start</var> to the first item in <var>tokens</var>.</p>\n     <li data-md>\n      <p>Remove the first item in <var>tokens</var>.</p>\n     <li data-md>\n      <p>If <var>start</var> is the empty string or contains any instances of U+002D (-), return null.</p>\n     <li data-md>\n      <p>If <var>tokens</var> is not <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#list-empty\" id=\"ref-for-list-empty②\">empty</a>:</p>\n      <ol>\n       <li data-md>\n        <p>Set <var>end</var> to the first item in <var>tokens</var>.</p>\n       <li data-md>\n        <p>If <var>end</var> is the empty string or contains any instances of U+002D (-), return null.</p>\n      </ol>\n     <li data-md>\n      <p>Return a new <a data-link-type=\"dfn\" href=\"#text-directive\" id=\"ref-for-text-directive③\">text directive</a>, with</p>\n      <dl class=\"props\">\n       <dt><a data-link-type=\"dfn\" href=\"#text-directive-prefix\" id=\"ref-for-text-directive-prefix\">prefix</a>\n       <dd>The <a data-link-type=\"dfn\" href=\"#percent-decode-a-text-directive-term\" id=\"ref-for-percent-decode-a-text-directive-term\">percent-decoding</a> of <var>prefix</var>\n       <dt><a data-link-type=\"dfn\" href=\"#text-directive-start\" id=\"ref-for-text-directive-start①\">start</a>\n       <dd>The <a data-link-type=\"dfn\" href=\"#percent-decode-a-text-directive-term\" id=\"ref-for-percent-decode-a-text-directive-term①\">percent-decoding</a> of <var>start</var>\n       <dt><a data-link-type=\"dfn\" href=\"#text-directive-end\" id=\"ref-for-text-directive-end\">end</a>\n       <dd>The <a data-link-type=\"dfn\" href=\"#percent-decode-a-text-directive-term\" id=\"ref-for-percent-decode-a-text-directive-term②\">percent-decoding</a> of <var>end</var>\n       <dt><a data-link-type=\"dfn\" href=\"#text-directive-suffix\" id=\"ref-for-text-directive-suffix\">suffix</a>\n       <dd>The <a data-link-type=\"dfn\" href=\"#percent-decode-a-text-directive-term\" id=\"ref-for-percent-decode-a-text-directive-term③\">percent-decoding</a> of <var>suffix</var>\n      </dl>\n    </ol>\n   </div>\n   <div class=\"algorithm\" data-algorithm=\"parse the fragment directive\">\n    <p>To <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"parse-the-fragment-directive\">parse the fragment directive</dfn>, an an <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#ascii-string\" id=\"ref-for-ascii-string③\">ASCII string</a> <var>fragment\ndirective</var>, run these steps:</p>\n    <div class=\"note\" role=\"note\"> This algorithm takes the fragment directive string (i.e. the part that follows \":~:\") and returns\n  a list of <a data-link-type=\"dfn\" href=\"#text-directive\" id=\"ref-for-text-directive④\">text directive</a> objects parsed from that string. Can return an empty list. </div>\n    <ol class=\"algorithm\">\n     <li data-md>\n      <p>Let <var>directives</var> be the result of <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#strictly-split\" id=\"ref-for-strictly-split①\">strictly\n  splitting</a> <var>fragment directive</var> on U+0026 (&amp;).</p>\n     <li data-md>\n      <p>Let <var>output</var> be an initially empty <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#list\" id=\"ref-for-list②\">list</a> of <a data-link-type=\"dfn\" href=\"#text-directive\" id=\"ref-for-text-directive⑤\">text directives</a>.</p>\n     <li data-md>\n      <p><a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#list-iterate\" id=\"ref-for-list-iterate\">For each</a> <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#string\" id=\"ref-for-string④\">string</a> <var>directive</var> in <var>directives</var>:</p>\n      <ol>\n       <li data-md>\n        <p>If <var>directive</var> does not <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#string-starts-with\" id=\"ref-for-string-starts-with①\">start with</a> \"<code>text=</code>\", then <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#iteration-continue\" id=\"ref-for-iteration-continue\">continue</a>.</p>\n       <li data-md>\n        <p>Let <var>text directive value</var> be the <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#code-point-substring-to-the-end-of-the-string\" id=\"ref-for-code-point-substring-to-the-end-of-the-string②\">code point substring</a> from 5 to the end of <var>directive</var>.</p>\n        <div class=\"note\" role=\"note\">Note: this may be the empty string.</div>\n       <li data-md>\n        <p>Let <var>parsed text directive</var> be the result of <a data-link-type=\"dfn\" href=\"#parse-a-text-directive\" id=\"ref-for-parse-a-text-directive\">parsing</a> <var>text\n  directive value</var>.</p>\n       <li data-md>\n        <p>If <var>parsed text directive</var> is non-null, <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#list-append\" id=\"ref-for-list-append\">append</a> it to <var>output</var>.</p>\n      </ol>\n     <li data-md>\n      <p>Return <var>output</var>.</p>\n    </ol>\n   </div>\n   <h4 class=\"heading settled\" data-level=\"3.4.1\" id=\"invoking-text-directives\"><span class=\"secno\">3.4.1. </span><span class=\"content\">Invoking Text Directives</span><a class=\"self-link\" href=\"#invoking-text-directives\"></a></h4>\n   <p>This section describes how text directives in a document’s <a data-link-type=\"dfn\" href=\"#document-pending-text-directives\" id=\"ref-for-document-pending-text-directives①\">pending text directives</a> are\nprocessed and invoked to cause indication of the relevant text passages.</p>\n   <div class=\"note\" role=\"note\">\n     The summarized changes in this section: \n    <ul>\n     <li data-md>\n      <p>Modify the indicated part processing model to try processing <a data-link-type=\"dfn\" href=\"#document-pending-text-directives\" id=\"ref-for-document-pending-text-directives②\">pending text directives</a> into a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range\">range</a> that will be returned as the indicated part.</p>\n     <li data-md>\n      <p>Modify \"scrolling to a fragment\" to correctly scroll and set the Document’s target element in the case\nof a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range①\">range</a> based indicated part.</p>\n     <li data-md>\n      <p>Ensure <a data-link-type=\"dfn\" href=\"#document-pending-text-directives\" id=\"ref-for-document-pending-text-directives③\">pending text directives</a> is reset to null when the user agent has finished the\nfragment search for the current navigation/traversal.</p>\n     <li data-md>\n      <p>If the user agent finishes searching for a text directive, ensure it tries the regular\nfragment as a fallback.</p>\n    </ul>\n   </div>\n   <p>In <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#the-indicated-part-of-the-document\"> indicated part</a>, enable a fragment to indicate a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range②\">range</a>. Make the following changes:</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#scrolling-to-a-fragment\"><cite>HTML</cite> § 7.4.6.3 Scrolling to a fragment</a>:</strong></p>\n    <div class=\"monkeypatch\">\n      For an HTML document <var>document</var>, the following processing model must be followed to determine\n  its indicated part: \n     <ol>\n      <li data-md>\n       <p><span class=\"diff\">Let <var>text directives</var> be the document’s <a data-link-type=\"dfn\" href=\"#document-pending-text-directives\" id=\"ref-for-document-pending-text-directives④\">pending text directives</a>. </span></p>\n      <li data-md>\n       <p><span class=\"diff\">If <var>text directives</var> is non-null then:</span></p>\n       <ol>\n        <li data-md>\n         <p><span class=\"diff\">Let <var>ranges</var> be a <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#list\" id=\"ref-for-list③\">list</a> that is the result of running\n  the <a data-link-type=\"dfn\" href=\"#invoke-text-directives\" id=\"ref-for-invoke-text-directives\">invoke text directives</a> steps with <var>text directives</var> and the document.</span></p>\n        <li data-md>\n         <p><span class=\"diff\">If <var>ranges</var> is non-empty, then:</span></p>\n         <ol>\n          <li data-md>\n           <p><span class=\"diff\">Let <var>firstRange</var> be the first item of <var>ranges</var>.</span></p>\n          <li data-md>\n           <p><span class=\"diff\">Visually indicate each <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range③\">range</a> in <var>ranges</var> in an <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#implementation-defined\" id=\"ref-for-implementation-defined\">implementation-defined</a> way. The indication must not be observable from author\n  script. See <a href=\"#indicating-the-text-match\">§ 3.7 Indicating The Text Match</a>.</span></p>\n           <div class=\"note\" role=\"note\"> The first <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range④\">range</a> in <var>ranges</var> is the one that gets scrolled into view but all\n    ranges should be visually indicated to the user. </div>\n          <li data-md>\n           <p><span class=\"diff\">Set <var>firstRange</var> as <var>document</var>’s indicated part, return.</span></p>\n         </ol>\n       </ol>\n      <li data-md>\n       <p>Let fragment be document’s URL’s fragment.</p>\n      <li data-md>\n       <p>If fragment is the empty string, then return the special value top of the document.</p>\n      <li data-md>\n       <p>Let potentialIndicatedElement be the result of finding a potential indicated element given\n  document and fragment.</p>\n      <li data-md>\n       <p>...</p>\n     </ol>\n    </div>\n   </blockquote>\n   <p>In <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#scroll-to-the-fragment-identifier\" id=\"ref-for-scroll-to-the-fragment-identifier\">scroll to the fragment</a>, handle an indicated part that is a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range⑤\">range</a> and also\nprevent fragment scrolling if the force-load-at-top policy is enabled. Make the following changes:</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#scrolling-to-a-fragment\"><cite>HTML</cite> § 7.4.6.3 Scrolling to a fragment</a>:</strong></p>\n    <div class=\"monkeypatch\">\n     <ol>\n      <li data-md>\n       <p>If document’s indicated part is null, then set document’s target element to null.</p>\n      <li data-md>\n       <p>Otherwise, if document’s indicated part is top of the document, then:</p>\n       <ol>\n        <li data-md>\n         <p>Set document’s target element to null.</p>\n        <li data-md>\n         <p>Scroll to the beginning of the document for document.</p>\n        <li data-md>\n         <p>Return.</p>\n       </ol>\n      <li data-md>\n       <p>Otherwise:</p>\n       <ol>\n        <li data-md>\n         <p class=\"assertion\">Assert: document’s indicated part is an element <span class=\"diff\">or it is a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range⑥\">range</a>.</span></p>\n        <li data-md>\n         <p><span class=\"diff\">Let <var>scrollTarget</var> be <var>document</var>’s indicated part.</span></p>\n        <li data-md>\n         <p><span class=\"diff\">Let <var>target</var> be <var>scrollTarget</var>.</span></p>\n        <li data-md>\n         <p><span class=\"diff\">If <var>target</var> is a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range⑦\">range</a>, then:</span></p>\n         <ol>\n          <li data-md>\n           <p><span class=\"diff\">Set <var>target</var> to be the <a data-link-type=\"dfn\" href=\"#first-common-ancestor\" id=\"ref-for-first-common-ancestor\">first common ancestor</a> of <var>target</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start-node\" id=\"ref-for-concept-range-start-node\">start node</a> and <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-end-node\" id=\"ref-for-concept-range-end-node\">end node</a>.</span></p>\n          <li data-md>\n           <p><span class=\"diff\">While <var>target</var> is non-null and is not an <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-element\" id=\"ref-for-concept-element\">element</a>, set <var>target</var> to <var>target</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-tree-parent\" id=\"ref-for-concept-tree-parent\">parent</a>.</span></p>\n           <div class=\"issue\" id=\"issue-424a4e25\"><a class=\"self-link\" href=\"#issue-424a4e25\"></a> What should be set as target if inside a shadow tree? <a href=\"https://github.com/WICG/scroll-to-text-fragment/issues/190\">#190</a> </div>\n         </ol>\n        <li data-md>\n         <p><span class=\"diff\">Assert: <var>target</var> is an <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-element\" id=\"ref-for-concept-element①\">element</a>.</span></p>\n        <li data-md>\n         <p>Set <var>document</var>’s target element to <var>target</var>.</p>\n        <li data-md>\n         <p>Run the ancestor details revealing algorithm on <var>target</var>.</p>\n        <li data-md>\n         <p>Run the ancestor hidden-until-found revealing algorithm on <var>target</var>.</p>\n         <div class=\"issue\" id=\"issue-10739530\"><a class=\"self-link\" href=\"#issue-10739530\"></a> These revealing algorithms currently wont work well since <var>target</var> could be an\n      ancestor or even the root document node. Issue <a href=\"https://github.com/WICG/scroll-to-text-fragment/issues/89\">#89</a> proposes\n      restricting matches to <code>contain:style layout</code> blocks which would resolve this\n      problem. </div>\n        <li data-md>\n         <p><span class=\"diff\">Let <var>blockPosition</var> be \"center\" if <var>scrollTarget</var> is a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range⑧\">range</a>,\n  \"start\" otherwise.</span></p>\n         <div class=\"note\" role=\"note\"> Scrolling to a text directive centers it in the block flow direction. </div>\n        <li data-md>\n         <strike class=\"diff\">Scroll <var>target</var> into view, with behavior set to \"auto\", block set to\n  \"start\", and inline set to \"nearest\".</strike>\n        <li value=\"10\">\n         <span class=\"diff\"><a data-link-type=\"dfn\" href=\"https://drafts.csswg.org/cssom-view-1/#scroll-a-target-into-view\" id=\"ref-for-scroll-a-target-into-view\">scroll a target into view</a>,\n  with <em>target</em> set to <var>scrollTarget</var>, <em>behavior</em> set to \"auto\", <em>block</em> set to <var>blockPosition</var>, and <em>inline</em> set to \"nearest\".</span> \n         <p><span class=\"diff\">Implementations MAY avoid scrolling to the target if it is\n  produced from a <a data-link-type=\"dfn\" href=\"#text-directive\" id=\"ref-for-text-directive⑥\">text directive</a>.</span></p>\n        <p></p>\n        <li data-md>\n         <p>Run the focusing steps for target, with the Document’s viewport as the fallback target.</p>\n         <div class=\"issue\" id=\"issue-e253a983\"><a class=\"self-link\" href=\"#issue-e253a983\"></a>Implementation note: Blink doesn’t currently set focus for text\n  fragments, it probably should? TODO: file crbug.</div>\n        <li data-md>\n         <p>Move the sequential focus navigation starting point to target.</p>\n       </ol>\n     </ol>\n    </div>\n   </blockquote>\n   <p>The next two monkeypatches ensure the user agent clears <a data-link-type=\"dfn\" href=\"#document-pending-text-directives\" id=\"ref-for-document-pending-text-directives⑤\">pending text directives</a> when\nthe fragment search is complete. In the case where a text directive search finishes because parsing\nhas stopped, it tries one more search for a non-text directive fragment.</p>\n   <p>In the definition of <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#try-to-scroll-to-the-fragment\" id=\"44bd3acf0\"> try to scroll to the fragment</a>:</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#scrolling-to-a-fragment\"><cite>HTML</cite> § 7.4.6.3 Scrolling to a fragment</a>:</strong></p>\n    <div class=\"monkeypatch\">\n      To try to scroll to the fragment for a Document <var>document</var>, perform the following steps in\n  parallel: \n     <ol>\n      <li data-md>\n       <p>Wait for an implementation-defined amount of time. (This is intended to allow the user agent\n  to optimize the user experience in the face of performance concerns.)</p>\n      <li data-md>\n       <p>Queue a global task on the navigation and traversal task source given document’s relevant\n  global object to run these steps:</p>\n       <ol>\n        <li data-md>\n         <strike class=\"diff\">If document has no parser, or its parser has stopped parsing, or the user agent\n  has reason to believe the user is no longer interested in scrolling to the fragment, then\n  abort these steps.</strike>\n        <li class=\"diff\" value=\"1\">\n         If the user agent has reason to believe the user is no longer interested in scrolling to\n  the fragment, then: \n         <ol>\n          <li data-md>\n           <p><span class=\"diff\">Set <a data-link-type=\"dfn\" href=\"#document-pending-text-directives\" id=\"ref-for-document-pending-text-directives⑥\">pending text directives</a> to null.</span></p>\n          <li data-md>\n           <p><span class=\"diff\">Abort these steps.</span></p>\n         </ol>\n        <li data-md>\n         <p><span class=\"diff\">If the document has no parser, or its parser has stopped parsing,\n  then:</span></p>\n        <p></p>\n        <ol>\n         <li data-md>\n          <p><span class=\"diff\">If <a data-link-type=\"dfn\" href=\"#document-pending-text-directives\" id=\"ref-for-document-pending-text-directives⑦\">pending text directives</a> is not null, then:</span></p>\n          <ol>\n           <li data-md>\n            <p><span class=\"diff\">Set <a data-link-type=\"dfn\" href=\"#document-pending-text-directives\" id=\"ref-for-document-pending-text-directives⑧\">pending text directives</a> to null.</span></p>\n           <li data-md>\n            <p><span class=\"diff\"><a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#scroll-to-the-fragment-identifier\" id=\"ref-for-scroll-to-the-fragment-identifier①\">Scroll to the fragment</a> given <var>document</var>.</span></p>\n          </ol>\n         <li data-md>\n          <p><span class=\"diff\">Abort these steps.</span></p>\n        </ol>\n        <li data-md>\n         <p>Scroll to the fragment given document.</p>\n        <li data-md>\n         <p>If document’s indicated part is still null, then try to scroll to the fragment for\n  document. <span class=\"diff\">Otherwise, set <a data-link-type=\"dfn\" href=\"#document-pending-text-directives\" id=\"ref-for-document-pending-text-directives⑨\">pending text directives</a> to\n  null.</span></p>\n       </ol>\n     </ol>\n    </div>\n   </blockquote>\n   <p>In the definition of <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate-fragid\" id=\"319d7c292\"> navigate to a fragment</a>:</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#scroll-to-fragid\"><cite>HTML</cite> § 7.4.2.3.3 Fragment navigations</a>:</strong></p>\n    <div class=\"monkeypatch\">\n     To navigate to a fragment given navigable <var>navigable</var>, ...: \n     <ol>\n      <li data-md>\n       <p>...</p>\n      <li value=\"8\">Update document for history step application given navigable’s active\ndocument, historyEntry, true, scriptHistoryIndex, and scriptHistoryLength. \n      <li data-md>\n       <p>Scroll to the fragment given navigable’s active document.</p>\n      <li class=\"diff\">Set <var>navigable</var>’s active document’s <a data-link-type=\"dfn\" href=\"#document-pending-text-directives\" id=\"ref-for-document-pending-text-directives①⓪\">pending text directives</a> to\nnull.\n      <li data-md>\n       <p>Let traversable be navigable’s traversable navigable.</p>\n      <li data-md>\n       <p>...</p>\n     </ol>\n    </div>\n   </blockquote>\n   <p>Scrolling to the indicated part is only one of several things that happens from \"scroll to the\nfragment\". Rename it and related definitions:</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#scroll-to-fragid\"><cite>HTML</cite> § 7.4.2.3.3 Fragment navigations</a>:</strong></p>\n    <p>Rename <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#scroll-to-fragid\"><cite>HTML</cite> § 7.4.2.3.3 Fragment navigations</a> and related steps to \"indicating a fragment\" to reflect its\n  broader effects.</p>\n   </blockquote>\n   <h3 class=\"heading settled\" data-level=\"3.5\" id=\"security-and-privacy\"><span class=\"secno\">3.5. </span><span class=\"content\">Security and Privacy</span><a class=\"self-link\" href=\"#security-and-privacy\"></a></h3>\n   <h4 class=\"heading settled\" data-level=\"3.5.1\" id=\"motivation\"><span class=\"secno\">3.5.1. </span><span class=\"content\">Motivation</span><a class=\"self-link\" href=\"#motivation\"></a></h4>\n   <div class=\"note\" role=\"note\">This section is non-normative</div>\n   <p>Care must be taken when implementing <a data-link-type=\"dfn\" href=\"#text-directive\" id=\"ref-for-text-directive⑦\">text directive</a> so that it\ncannot be used to exfiltrate information across origins. Scripts can navigate a\npage to a cross-origin URL with a <a data-link-type=\"dfn\" href=\"#text-directive\" id=\"ref-for-text-directive⑧\">text directive</a>. If a malicious\nactor can determine that the text fragment was successfully found in victim\npage as a result of such a navigation, they can infer the existence of any text\non the page.</p>\n   <p>The processing model in the following subsections restricts the feature to\nmitigate the expected attack vectors. In summary, text directives are restricted\nto:</p>\n   <ul>\n    <li data-md>\n     <p>top level navigables (i.e. no iframes).</p>\n     <ul>\n      <li data-md>\n       <p class=\"issue\" id=\"issue-35f490f0\"><a class=\"self-link\" href=\"#issue-35f490f0\"></a> This isn’t strictly true, Chrome\nallows this for same-origin initiators. Need to update the spec on this\npoint. <a href=\"https://github.com/WICG/scroll-to-text-fragment/issues/240\">[Issue #WICG/scroll-to-text-fragment#240]</a></p>\n     </ul>\n    <li data-md>\n     <p>navigations that are the result of a user action</p>\n    <li data-md>\n     <p>in cases where the navigation has a cross-origin initiator, the destination\nmust be opener isolated (i.e. no references to its global objects in other\ndocuments)</p>\n   </ul>\n   <h4 class=\"heading settled\" data-level=\"3.5.2\" id=\"scroll-on-navigation\"><span class=\"secno\">3.5.2. </span><span class=\"content\">Scroll On Navigation</span><a class=\"self-link\" href=\"#scroll-on-navigation\"></a></h4>\n   <p>A UA may choose to automatically scroll a matched text passage into view. This\ncan be a convenient experience for the user but does present some risks that\nimplementing UAs need to be aware of.</p>\n   <p>There are known (and potentially unknown) ways a scroll on navigation might be\ndetectable and distinguished from natural user scrolls.</p>\n   <div class=\"example\" id=\"example-fe268bc5\"><a class=\"self-link\" href=\"#example-fe268bc5\"></a> An origin embedded in an iframe in the target page registers an\n  IntersectionObserver and determines in the first 500ms of page load whether\n  a scroll has occurred. This scroll can be indicative of whether the text\n  fragment was successfully found on the page. </div>\n   <div class=\"example\" id=\"example-ce37442a\"><a class=\"self-link\" href=\"#example-ce37442a\"></a> Two users share the same network on which traffic is visible between them.\n  A malicious user sends the victim a link with a text fragment to a\n  page. The searched-for text appears nearby to a resource located on a unique\n  (on the page) domain. The attacker may be able to infer the success or failure\n  of the fragment search based on the order of requests for DNS lookup. </div>\n   <div class=\"example\" id=\"example-2e4f39df\"><a class=\"self-link\" href=\"#example-2e4f39df\"></a> An attacker sends a link to a victim, sending them to a page that displays\n  a private token. The attacker asks the victim to read back the token. Using\n  a text fragment, the attacker gets the page to load for the victim such that\n  warnings about keeping the token secret are scrolled out of view. </div>\n   <p>All known cases like this rely on specific circumstances about the target page\nso don’t apply generally. With additional restrictions about when the text\nfragment can invoke an attacker is further restricted. Nonetheless, different\nUAs can come to different conclusions about whether these risks are acceptable.\nUAs need to consider these factors when determining whether to scroll as part of\nnavigating to a text fragment.</p>\n   <p>Conforming UAs may choose not to scroll automatically on navigation. Such UAs\nmay, instead, provide UI to initiate the scroll (\"click to scroll\") or none\nat all. In these cases UA should provide some indication to the user that an\nindicated passage exists further down on the page.</p>\n   <p>The examples above illustrate that in specific circumstances, it can be\npossible for an attacker to extract 1 bit of information about content on the\npage. However, care must be taken so that such opportunities cannot be\nexploited to extract arbitrary content from the page by repeating the attack.\nFor this reason, restrictions based on user activation and browsing context\nisolation are very important and must be implemented.</p>\n   <div class=\"note\" role=\"note\">\n     Browsing context isolation ensures that no other document can script the\n  target document which helps reduce the attack surface. \n    <p>However, it also ensures any malicious use is difficult to hide. A browsing\n  context that’s the only one in a group will be a top level browsing context\n  (i.e. a full tab/window).</p>\n   </div>\n   <p>If a UA does choose to scroll automatically, it must ensure no scrolling is\nperformed while the document is in the background (for example, in an inactive\ntab). This ensures any malicious usage is visible to the user and prevents\nattackers from trying to secretly automate a search in background documents.</p>\n   <p>If a UA chooses not to scroll automatically, it must scroll a fallback\nelement-id into view, if provided, regardless of whether a text fragment was\nmatched. Not doing so would allow detecting the text fragment match based on\nwhether the element-id was scrolled.</p>\n   <h4 class=\"heading settled\" data-level=\"3.5.3\" id=\"search-timing\"><span class=\"secno\">3.5.3. </span><span class=\"content\">Search Timing</span><a class=\"self-link\" href=\"#search-timing\"></a></h4>\n   <p>A naive implementation of the text search algorithm could allow information\nexfiltration based on runtime duration differences between a matching and non-\nmatching query. If an attacker could find a way to synchronously navigate\nto a <a data-link-type=\"dfn\" href=\"#text-directive\" id=\"ref-for-text-directive⑨\">text directive</a>-invoking URL, they would be able to determine\nthe existence of a text snippet by measuring how long the navigation call takes.</p>\n   <div class=\"note\" role=\"note\"> The restrictions in <a href=\"#restricting-the-text-fragment\">§ 3.5.4 Restricting the Text Fragment</a> prevent this\n  specific case; in particular, the no-same-document-navigation restriction.\n  However, these restrictions are provided as multiple layers of defence. </div>\n   <p>For this reason, the implementation <em>must ensure the runtime of <a href=\"#navigating-to-text-fragment\">§ 3.6 Navigating to a Text Fragment</a> steps does not differ based on whether a match\nhas been successfully found</em>.</p>\n   <p>This specification does not specify exactly how a UA achieves this as there are\nmultiple solutions with differing tradeoffs. For example, a UA <em>may</em> continue to walk the tree even after a match is found in <a data-link-type=\"dfn\" href=\"#find-a-range-from-a-text-directive\" id=\"ref-for-find-a-range-from-a-text-directive\">find a range from a\ntext directive</a>.  Alternatively, it <em>may</em> schedule an asynchronous task\nto find and set the <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-document\" id=\"ref-for-concept-document①\">Document</a>'s indicated part.</p>\n   <h4 class=\"heading settled\" data-level=\"3.5.4\" id=\"restricting-the-text-fragment\"><span class=\"secno\">3.5.4. </span><span class=\"content\">Restricting the Text Fragment</span><a class=\"self-link\" href=\"#restricting-the-text-fragment\"></a></h4>\n   <div class=\"note\" role=\"note\">\n     This section integrates with HTML navigation to restrict when an indicated text directive will\n  be allowed to scroll. In summary: \n    <ul>\n     <li data-md>\n      <p>Add a boolean <code>text directive user activation</code> to both Document and Request. This\n  flag is set on a document when created from a user activated navigation and consumed if a text\n  directive is scrolled. If unconsumed, it can be transfered to an outgoing navigation request.\n  This implements the user-activation-through-redirects behavior described in the note below.</p>\n     <li data-md>\n      <p>Define a series of checks, performed on a document and the user involvement and initiator origin\n  state of a navigation, to determine whether a text directive should be allowed to perform a\n  scroll.</p>\n     <li data-md>\n      <p>Compute the scroll permission from \"finalize a cross document navigation\" and from \"navigate to\n  a fragment steps\" and plumb it through to the \"scroll to the fragment\" steps where its used to\n  abort a text directive scroll.</p>\n    </ul>\n   </div>\n   <p>Amend the definition of a <a data-link-type=\"dfn\" href=\"https://fetch.spec.whatwg.org/#concept-request\" id=\"ref-for-concept-request\">request</a> and of a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-document\" id=\"ref-for-concept-document②\">Document</a> to include a new\nboolean <a data-link-type=\"dfn\" href=\"#document-text-directive-user-activation\" id=\"ref-for-document-text-directive-user-activation\">text directive user activation</a> field:</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a data-link-type=\"biblio\" href=\"#biblio-fetch\" title=\"Fetch Standard\">[FETCH]</a>:</strong></p>\n    <p>A <a data-link-type=\"dfn\" href=\"https://fetch.spec.whatwg.org/#concept-request\" id=\"ref-for-concept-request①\">request</a> has an associated boolean <dfn class=\"dfn-paneled\" data-dfn-for=\"request\" data-dfn-type=\"dfn\" data-noexport id=\"request-text-directive-user-activation\">text directive user activation</dfn>,\n  initially false.</p>\n   </blockquote>\n   <blockquote>\n    <p><strong>Monkeypatching <a data-link-type=\"biblio\" href=\"#biblio-html\" title=\"HTML Standard\">[HTML]</a>:</strong></p>\n    <p>Each <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-document\" id=\"ref-for-concept-document③\">Document</a> has a <dfn class=\"dfn-paneled\" data-dfn-for=\"document\" data-dfn-type=\"dfn\" data-noexport id=\"document-text-directive-user-activation\">text directive user activation</dfn>, which is a boolean,\n  initially false.</p>\n    <div class=\"note\" role=\"note\">\n      <a data-link-type=\"dfn\" href=\"#document-text-directive-user-activation\" id=\"ref-for-document-text-directive-user-activation①\">text directive user activation</a> provides the necessary user gesture signal to allow\n    a single activation of a text fragment. It is set to true during document loading only if the\n    navigation occurred as a result of a user activation and is propagated across client-side\n    redirects. \n     <p>If a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-document\" id=\"ref-for-concept-document④\">Document</a>'s <a data-link-type=\"dfn\" href=\"#document-text-directive-user-activation\" id=\"ref-for-document-text-directive-user-activation②\">text directive user activation</a> isn’t used to activate a text\n    fragment, it is instead used to set a new navigation <a data-link-type=\"dfn\" href=\"https://fetch.spec.whatwg.org/#concept-request\" id=\"ref-for-concept-request②\">request</a>'s <a data-link-type=\"dfn\" href=\"#request-text-directive-user-activation\" id=\"ref-for-request-text-directive-user-activation\">text directive user activation</a> to true. In this way, a <a data-link-type=\"dfn\" href=\"#document-text-directive-user-activation\" id=\"ref-for-document-text-directive-user-activation③\">text directive user activation</a> can be propagated\n    from one <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-document\" id=\"ref-for-concept-document⑤\">Document</a> to another across a navigation.</p>\n     <p>Both <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-document\" id=\"ref-for-concept-document⑥\">Document</a>'s <a data-link-type=\"dfn\" href=\"#document-text-directive-user-activation\" id=\"ref-for-document-text-directive-user-activation④\">text directive user activation</a> and <a data-link-type=\"dfn\" href=\"https://fetch.spec.whatwg.org/#concept-request\" id=\"ref-for-concept-request③\">request</a>'s <a data-link-type=\"dfn\" href=\"#request-text-directive-user-activation\" id=\"ref-for-request-text-directive-user-activation①\">text directive user activation</a> are always set to false when used, such that a\n    single user activation cannot be reused to activate more than one text fragment.</p>\n    </div>\n   </blockquote>\n   <div class=\"note\" role=\"note\">\n    <p>\n      This mechanism allows text fragments to activate through a common redirect\n    technique used by many popular web sites. Such sites redirect users to\n    their intended destination by responding with a 200 status code containing\n    script to set the \n     <tt>window.location</tt>\n     . \n    </p>\n    <p>\n      Unlike real HTTP (\n     <tt>status 3xx</tt>\n     ) redirects, these \"client-side\"\n    redirects cannot propagate the fact that the navigation is the result of a\n    user gesture. The <a data-link-type=\"dfn\" href=\"#document-text-directive-user-activation\" id=\"ref-for-document-text-directive-user-activation⑤\">text directive user activation</a> mechanism allows passing\n    through this specifically scoped user-activation through such navigations.\n    This means a page is able to programmatically navigate to a text fragment, a\n    single time, as if it has a user gesture. However, since this resets <code>text fragment user\n    activation</code>, further text fragment navigations will not activation without a new user gesture. \n    </p>\n    <p> The following diagram demonstrates how the flag is used to activate a text\n    fragment through a client-side redirect service: </p>\n    <p><img alt=\"Diagram showing how a text fragment flag is set and used\" height=\"671\" src=\"https://raw.githubusercontent.com/WICG/scroll-to-text-fragment/master/text_fragment_activation_flag.png\" style=\"margin-left:auto;margin-right:auto;display:block\" width=\"745\"></p>\n    <p> See <a href=\"redirects.md\">redirects.md</a> for a more in-depth discussion. </p>\n   </div>\n   <p>Amend the <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#create-navigation-params-by-fetching\" id=\"ref-for-create-navigation-params-by-fetching\">create navigation params by fetching</a> steps to transfer the <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/document-sequences.html#nav-document\" id=\"ref-for-nav-document①\">active\ndocument</a>'s <a data-link-type=\"dfn\" href=\"#document-text-directive-user-activation\" id=\"ref-for-document-text-directive-user-activation⑥\">text directive user activation</a> value into <var>request</var>’s <a data-link-type=\"dfn\" href=\"#request-text-directive-user-activation\" id=\"ref-for-request-text-directive-user-activation②\">text directive user activation</a>.</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a data-link-type=\"biblio\" href=\"#biblio-html\" title=\"HTML Standard\">[HTML]</a>:</strong></p>\n    <div class=\"monkeypatch\">\n     <ol>\n      <li data-md>\n       <p class=\"assertion\">Assert: this is running in parallel.</p>\n      <li data-md>\n       <p>Let documentResource be entry’s document state’s resource.</p>\n      <li data-md>\n       <p>Let <var>request</var> be a new request, with</p>\n       <dl class=\"props\">\n        <dt>url\n        <dd><var>entry</var>’s URL\n        <dt>...\n        <dd>...\n        <dt>referrer policy\n        <dd><var>entry</var>’s document state’s request referrer policy\n        <dt><span class=\"diff\"><a data-link-type=\"dfn\" href=\"#request-text-directive-user-activation\" id=\"ref-for-request-text-directive-user-activation③\">text directive user activation</a></span>\n        <dd><span class=\"diff\"><var>navigable</var>’s <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/document-sequences.html#nav-document\" id=\"ref-for-nav-document②\">active document</a>'s <a data-link-type=\"dfn\" href=\"#document-text-directive-user-activation\" id=\"ref-for-document-text-directive-user-activation⑦\">text directive user activation</a></span>\n       </dl>\n      <li data-md>\n       <p><span class=\"diff\">Set <var>navigable</var>’s <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/document-sequences.html#nav-document\" id=\"ref-for-nav-document③\">active document</a>'s <a data-link-type=\"dfn\" href=\"#document-text-directive-user-activation\" id=\"ref-for-document-text-directive-user-activation⑧\">text directive\n  user activation</a> to false.</span></p>\n      <li data-md>\n       <p>If documentResource is a POST resource, then:</p>\n       <ol>\n        <li data-md>\n         <p>...</p>\n       </ol>\n     </ol>\n    </div>\n   </blockquote>\n   <p>Amend the definition of <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigation-params\" id=\"ref-for-navigation-params\">navigation params</a> to include a new field:</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a data-link-type=\"biblio\" href=\"#biblio-html\" title=\"HTML Standard\">[HTML]</a>:</strong></p>\n    <dl>\n     <dt><dfn class=\"dfn-paneled\" data-dfn-for=\"navigation params\" data-dfn-type=\"dfn\" data-noexport id=\"navigation-params-user-involvement\">user involvement</dfn>\n     <dd>A <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#user-navigation-involvement\" id=\"ref-for-user-navigation-involvement\">user navigation involvement</a> value.\n    </dl>\n   </blockquote>\n   <p>Initialize the <a data-link-type=\"dfn\" href=\"#navigation-params-user-involvement\" id=\"ref-for-navigation-params-user-involvement\">user involvement</a> value everywhere a navigation params is\ncreated. Specifically: initialize it to true in the <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#create-navigation-params-by-fetching\" id=\"ref-for-create-navigation-params-by-fetching①\">create navigation params by\nfetching</a> case:</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a data-link-type=\"biblio\" href=\"#biblio-html\" title=\"HTML Standard\">[HTML]</a>:</strong></p>\n    <div class=\"monkeypatch\">\n      To create navigation params by fetching given a session history entry entry, a navigable\n  navigable, a source snapshot params sourceSnapshotParams, a target snapshot params\n  targetSnapshotParams, a string cspNavigationType, a navigation ID-or-null navigationId, a\n  NavigationTimingType navTimingType, <span class=\"diff\">and a <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#user-navigation-involvement\" id=\"ref-for-user-navigation-involvement①\">user navigation\n  involvement</a> <var>user involvement</var></span>, perform the following steps. They return a navigation params,\n  a non-fetch scheme navigation params, or null. \n     <ol>\n      <li data-md>\n       <p class=\"assertion\">Assert: this is running in parallel.</p>\n      <li data-md>\n       <p>...</p>\n      <li value=\"23\">Let resultPolicyContainer be the result of determining navigation params policy container given\n  response’s URL, entry’s document state’s history policy container, sourceSnapshotParams’s source\n  policy container, null, and responsePolicyContainer.\n      <li data-md>\n       <p>If navigable’s container is an iframe, and response’s timing allow passed flag is set, then\n  set container’s pending resource-timing start time to null.</p>\n      <li data-md>\n       <p>Return a new navigation params, with</p>\n       <dl>\n        <dt>id\n        <dd>navigationId\n        <dt>...\n        <dd>...\n        <dt>about base URL\n        <dd>entry’s document state’s about base URL\n        <dt class=\"diff\"><a data-link-type=\"dfn\" href=\"#navigation-params-user-involvement\" id=\"ref-for-navigation-params-user-involvement①\">user involvement</a>\n        <dd class=\"diff\"><var>user involvement</var>\n       </dl>\n     </ol>\n    </div>\n   </blockquote>\n   <p>Amend the <a href=\"https://html.spec.whatwg.org/multipage/document-lifecycle.html#initialise-the-document-object\"> create and initialize a Document object</a> steps to compute and store the <a data-link-type=\"dfn\" href=\"#document-text-directive-user-activation\" id=\"ref-for-document-text-directive-user-activation⑨\">text directive\nuser activation</a> flag:</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a data-link-type=\"biblio\" href=\"#biblio-html\" title=\"HTML Standard\">[HTML]</a>:</strong></p>\n    <div class=\"monkeypatch\">\n     <ol start=\"18\">\n      <li data-md>\n       <p>Process link headers given document, navigationParams’s response, and \"pre-media\".</p>\n      <li data-md>\n       <div class=\"diff\">\n        Set <var>document</var>’s <a data-link-type=\"dfn\" href=\"#document-text-directive-user-activation\" id=\"ref-for-document-text-directive-user-activation①⓪\">text directive user activation</a> to true if any of the following\nconditions hold, false otherwise: \n        <ul>\n         <li data-md>\n          <p><var>navigationParams</var>’s <a data-link-type=\"dfn\" href=\"#navigation-params-user-involvement\" id=\"ref-for-navigation-params-user-involvement②\">user involvement</a> is \"<code>activation</code>\";</p>\n         <li data-md>\n          <p><var>navigationParams</var>’s <a data-link-type=\"dfn\" href=\"#navigation-params-user-involvement\" id=\"ref-for-navigation-params-user-involvement③\">user involvement</a> is \"<code>browser UI</code>\"; or</p>\n         <li data-md>\n          <p><var>navigationParams</var>’s <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigation-params-request\">request</a>’s <a data-link-type=\"dfn\" href=\"#request-text-directive-user-activation\" id=\"ref-for-request-text-directive-user-activation④\">text directive user activation</a> is true.</p>\n          <div class=\"note\" role=\"note\"> It’s important that <a data-link-type=\"dfn\" href=\"#document-text-directive-user-activation\" id=\"ref-for-document-text-directive-user-activation①①\">text directive user activation</a> not be copyable so that\n  only one text fragment can be activated per user-activated navigation. </div>\n        </ul>\n       </div>\n      <li data-md>\n       <p>Return <var>document</var>.</p>\n     </ol>\n    </div>\n   </blockquote>\n   <p>A <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"text-directive-allowing-mime-type\">text directive allowing MIME type</dfn> is a <a data-link-type=\"dfn\" href=\"https://mimesniff.spec.whatwg.org/#mime-type\" id=\"ref-for-mime-type\">MIME type</a> whose <a data-link-type=\"dfn\" href=\"https://mimesniff.spec.whatwg.org/#mime-type-essence\" id=\"ref-for-mime-type-essence\">essence</a> is\n\"<code>text/html</code>\" or \"<code>text/plain</code>\".</p>\n   <p class=\"note\" role=\"note\"><span class=\"marker\">Note:</span> As noted in <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#scrolling-to-a-fragment\">scrolling\nto a fragment, fragment processing is defined individually by each MIME type. As such, the </a><a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#scroll-to-the-fragment-identifier\" id=\"ref-for-scroll-to-the-fragment-identifier②\">scroll to the fragment</a> steps where text directives are scrolled should only apply\nto text/html media types. However, in practice, web browsers tend to apply HTML fragment processing\nto other types, such as text/plain (e.g. add an element with an id to a text/plain document,\nnavigating to the fragment-id causes scrolling). While this is the case, enabling text directives in\ntext/plain documents is useful. Other types are explicitly disallowed to prevent the possibility of\nXS-Search attacks on potentially sensitive application data (e.g. text/css, application/json,\napplication/javascript, etc.).</p>\n   <p class=\"issue\" id=\"issue-0e1d8eda\"><a class=\"self-link\" href=\"#issue-0e1d8eda\"></a> Is this valid to say in the HTML spec?</p>\n   <div class=\"algorithm\" data-algorithm=\"check if a text directive can be scrolled\">\n     To <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"check-if-a-text-directive-can-be-scrolled\">check if a text directive can be scrolled</dfn>; given a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-document\" id=\"ref-for-concept-document⑦\">Document</a> <var>document</var>, an <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsers.html#concept-origin\" id=\"ref-for-concept-origin\">origin</a>-or-null <var>initiator origin</var>, and <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#user-navigation-involvement\" id=\"ref-for-user-navigation-involvement②\">user navigation involvement</a>-or-null <var>user involvement</var>, follow these steps: \n    <ol class=\"algorithm\">\n     <li data-md>\n      <p>If <var>document</var>’s <a data-link-type=\"dfn\" href=\"#document-pending-text-directives\" id=\"ref-for-document-pending-text-directives①①\">pending text directives</a> field is null or empty, return false.</p>\n     <li data-md>\n      <p>Let <var>is user involved</var> be true if: <var>document</var>’s <a data-link-type=\"dfn\" href=\"#document-text-directive-user-activation\" id=\"ref-for-document-text-directive-user-activation①②\">text directive user activation</a> is\ntrue, or <var>user involvement</var> is one of \"<code>activation</code>\" or \"<code>browser\nUI</code>\"; false otherwise.</p>\n     <li data-md>\n      <p>Set <var>document</var>’s <a data-link-type=\"dfn\" href=\"#document-text-directive-user-activation\" id=\"ref-for-document-text-directive-user-activation①③\">text directive user activation</a> to false.</p>\n     <li data-md>\n      <p>If <var>document</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-document-content-type\" id=\"ref-for-concept-document-content-type\">content type</a> is not a <a data-link-type=\"dfn\" href=\"#text-directive-allowing-mime-type\" id=\"ref-for-text-directive-allowing-mime-type\">text directive allowing MIME type</a>,\nreturn false.</p>\n     <li data-md>\n      <p>If <var>user involvement</var> is \"<code>browser UI</code>\", return true.</p>\n      <div class=\"note\" role=\"note\">\n       <p> If a navigation originates from browser UI, it’s always ok to allow it since it’ll be\n    user triggered and the page/script isn’t providing the text snippet. </p>\n       <p> Note: The intent in this item is to distinguish cases where the app/page is able to\n    control the URL from those that are fully under the user’s control. In the former we\n    want to prevent scrolling of the text fragment unless the destination is loaded in a\n    separate browsing context group (so that the source cannot both control the text snippet\n    and observe side-effects in the navigation). There are some cases where \"browser UI\" may\n    be a grey area in this regard. E.g. an \"open in new window\" context menu item when right\n    clicking on a link. </p>\n       <p> See <a href=\"https://w3c.github.io/webappsec-fetch-metadata/#directly-user-initiated\"> sec-fetch-site</a> in <a data-link-type=\"biblio\" href=\"#biblio-fetch-metadata\" title=\"Fetch Metadata Request Headers\">[FETCH-METADATA]</a> for a related discussion of how this applies. </p>\n      </div>\n     <li data-md>\n      <p>If <var>is user involved</var> is false, return false.</p>\n     <li data-md>\n      <p>If <var>document</var>’s <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/document-sequences.html#node-navigable\" id=\"ref-for-node-navigable\">node navigable</a> has a <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/document-sequences.html#nav-parent\" id=\"ref-for-nav-parent\">parent</a>, return false.</p>\n     <li data-md>\n      <p>If <var>initiator origin</var> is non-null and <var>document</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-document-origin\" id=\"ref-for-concept-document-origin\">origin</a> is <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsers.html#same-origin\" id=\"ref-for-same-origin\">same origin</a> with <var>initiator origin</var>, return true.</p>\n     <li data-md>\n      <p>If <var>document</var>’s <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/document-sequences.html#concept-document-bc\" id=\"ref-for-concept-document-bc\">browsing context</a>'s <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsers.html#tlbc-group\" id=\"ref-for-tlbc-group\">group</a>'s <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/document-sequences.html#browsing-context-set\" id=\"ref-for-browsing-context-set\">browsing context set</a> has length 1, return true.</p>\n      <div class=\"note\" role=\"note\"> i.e. Only allow navigation from a cross-origin element/script if the\n  document is loaded in a noopener context. That is, a new top level\n  browsing context group to which the navigator does not have script access\n  and which can be placed into a separate process. </div>\n     <li data-md>\n      <p>Otherwise, return false.</p>\n    </ol>\n   </div>\n   <p>Amend (the already amended, in <a href=\"#invoking-text-directives\">§ 3.4.1 Invoking Text Directives</a>) <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#scroll-to-the-fragment-identifier\" id=\"ref-for-scroll-to-the-fragment-identifier③\">scroll to the\nfragment</a> steps to add a new parameter, a boolean <var>allow text directive scroll</var>:</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#scrolling-to-a-fragment\"><cite>HTML</cite> § 7.4.6.3 Scrolling to a fragment</a>:</strong></p>\n    <div class=\"monkeypatch\">\n      To scroll to the fragment given a Document <var>document</var> <span class=\"diff\">and boolean <var>allow text\n  directive scroll</var></span>: \n     <ol>\n      <li data-md>\n       <p>If document’s indicated part is null, then set document’s target element to null.</p>\n      <li data-md>\n       <p>...</p>\n      <li data-md>\n       <p>Otherwise:</p>\n       <ol>\n        <li data-md>\n         <p class=\"assertion\">Assert: document’s indicated part is an element or it is a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range⑨\">range</a>.</p>\n        <li data-md>\n         <p>...</p>\n        <li value=\"4\">If <var>target</var> is a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range①⓪\">range</a>, then:\n        <ol>\n         <li data-md>\n          <p><span class=\"diff\">If <var>allow text directive scroll</var> is false, return.</span></p>\n         <li data-md>\n          <p>Set <var>target</var> to be the <a data-link-type=\"dfn\" href=\"#first-common-ancestor\" id=\"ref-for-first-common-ancestor①\">first common ancestor</a> of <var>target</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start-node\" id=\"ref-for-concept-range-start-node①\">start node</a> and <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-end-node\" id=\"ref-for-concept-range-end-node①\">end node</a>.</p>\n         <li data-md>\n          <p>...</p>\n        </ol>\n       </ol>\n     </ol>\n    </div>\n   </blockquote>\n   <p>Amend the <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#try-to-scroll-to-the-fragment\" id=\"ref-for-try-to-scroll-to-the-fragment\">try to scroll to the fragment</a> by adding a boolean flag <var>allow text\ndirective scroll</var> and replacing the steps of the task queued in step 2:</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a data-link-type=\"biblio\" href=\"#biblio-html\" title=\"HTML Standard\">[HTML]</a>:</strong></p>\n    <div class=\"monkeypatch\">\n      To try to scroll to the fragment for a Document <var>document</var>, <span class=\"diff\">with boolean <var>allow text directive scroll</var></span>, perform the following steps in parallel: \n     <ol>\n      <li data-md>\n       <p>Wait for an implementation-defined amount of time. (This is intended to allow the user agent\n  to optimize the user experience in the face of performance concerns.)</p>\n      <li data-md>\n       <p>Queue a global task on the navigation and traversal task source given document’s relevant\n  global object to run these steps:</p>\n       <ol>\n        <li data-md>\n         <p>If document has no parser, or its parser has stopped parsing, or the user\n  agent has reason to believe the user is no longer interested in scrolling to\n  the fragment, then abort these steps.</p>\n        <li data-md>\n         <p>Scroll to the fragment given <var>document</var> <span class=\"diff\">and <var>allow text directive\n  scroll</var>.</span></p>\n        <li data-md>\n         <p>If document’s indicated part is still null, then try to scroll to the fragment for <var>document</var><span class=\"diff\"> and <var>allow text directive scroll</var></span>.</p>\n       </ol>\n     </ol>\n    </div>\n   </blockquote>\n   <p>Amend the <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#update-document-for-history-step-application\" id=\"ref-for-update-document-for-history-step-application①\">update document for history step application</a> steps to take a boolean <var>allow text directive scroll</var> and use it when scrolling to a fragment:</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a data-link-type=\"biblio\" href=\"#biblio-html\" title=\"HTML Standard\">[HTML]</a>:</strong></p>\n    <div class=\"monkeypatch\">\n      To update document for history step application given a Document document, a session history\n  entry entry, a boolean doNotReactivate, integers scriptHistoryLength and scriptHistoryIndex,\n  an optional list of session history entries entriesForNavigationAPI, <span class=\"diff\">and a\n  boolean <var>allow text directive scroll</var></span>: \n     <ol>\n      <li data-md>\n       <p>Let documentIsNew be true if <var>document</var>’s latest entry is null; otherwise false.</p>\n      <li data-md>\n       <p>...</p>\n      <li value=\"5\">\n       If documentsEntryChanged is true, then: \n       <ol>\n        <li data-md>\n         <p>Let oldURL be document’s latest entry’s URL.</p>\n        <li data-md>\n         <p>...</p>\n       </ol>\n      <li data-md>\n       <p>If documentIsNew is true, then:</p>\n       <ol>\n        <li data-md>\n         <p>Try to scroll to the fragment with <var>document</var> <span class=\"diff\">and <var>allow text\n  directive scroll</var>.</span></p>\n       </ol>\n     </ol>\n    </div>\n   </blockquote>\n   <p>Amend the <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#apply-the-history-step\" id=\"ref-for-apply-the-history-step\">apply the history step</a> algorithm to take a boolean <var>allow text directive\nscroll</var> and pass it through when calling <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#update-document-for-history-step-application\" id=\"ref-for-update-document-for-history-step-application②\">update document for history step application </a>:</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a data-link-type=\"biblio\" href=\"#biblio-html\" title=\"HTML Standard\">[HTML]</a>:</strong></p>\n    <div class=\"monkeypatch\">\n     <p>To apply the history step given a non-negative integer step to a traversable navigable\ntraversable, with boolean checkForCancelation, source snapshot params-or-null\nsourceSnapshotParams, navigable-or-null initiatorToCheck, user navigation involvement-or-null\nuserInvolvementForNavigateEvents, <span class=\"diff\">and boolean <var>allow text directive scroll</var> (default false)</span> perform the following steps. They\nreturn \"initiator-disallowed\", \"canceled-by-beforeunload\", \"canceled-by-navigate\", or \"applied\".</p>\n     <ol start=\"14\">\n      <li data-md>\n       <p>While completedChangeJobs does not equal totalChangeJobs:</p>\n       <ol>\n        <li data-md>\n         <p>...</p>\n        <li value=\"11\">\n         Queue a global task on the navigation and traversal task source given\nnavigable’s active window to run the steps: \n         <ol>\n          <li data-md>\n           <p>If changingNavigableContinuation’s update-only is false, then:</p>\n           <ol>\n            <li data-md>\n             <p>...</p>\n            <li data-md>\n             <p>Activate history entry <var>targetEntry</var> for navigable.</p>\n           </ol>\n          <li data-md>\n           <p>Let updateDocument be an algorithm step which performs update document for history\nstep application given <var>targetEntry</var>’s document, <var>targetEntry</var>,\nchangingNavigableContinuation’s update-only, scriptHistoryLength,\nscriptHistoryIndex, entriesForNavigationAPI, <span class=\"diff\">and <var>allow text\ndirective scroll</var></span></p>\n          <li data-md>\n           <p>If <var>targetEntry</var>’s document is equal to displayedDocument, then perform\nupdateDocument.</p>\n         </ol>\n       </ol>\n      <li data-md>\n       <p>Let totalNonchangingJobs be the size of nonchangingNavigablesThatStillNeedUpdates.</p>\n     </ol>\n    </div>\n   </blockquote>\n   <p>Amend the <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#apply-the-push%2Freplace-history-step\" id=\"ref-for-apply-the-push%2Freplace-history-step\">apply the push/replace history step</a> to take and pass <var>allow text\ndirective scrolling</var> to apply the history step:</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a data-link-type=\"biblio\" href=\"#biblio-html\" title=\"HTML Standard\">[HTML]</a>:</strong></p>\n    <div class=\"monkeypatch\">\n      To apply the push/replace history step given a non-negative integer <var>step</var> to a traversable\n navigable <var>traversable</var>, <span class=\"diff\">with boolean <var>allow text directive scroll</var> (default\n false)</span>: \n     <p>Return the result of applying the history step <var>step</var> to <var>traversable</var> given false, null, null,\n null, <span class=\"diff\"><var>allow text directive scroll</var></span>.</p>\n    </div>\n   </blockquote>\n   <p class=\"note\" role=\"note\"><span class=\"marker\">Note:</span> The <var>allow text directive scroll</var> is intentionally not set for traversal and reload cases.\nThis avoids extensive plumbing and checks for initiator origin and user involvement and history\nscroll state should take precedence anyway. The text directive may still be used as the indicated\npart of the document so highlights will be restored.</p>\n   <p>Amend the <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#finalize-a-cross-document-navigation\" id=\"ref-for-finalize-a-cross-document-navigation\">finalize a cross-document navigation</a> to take a <var>user involvement</var> parameter and compute and pass <var>allow text directive scrolling</var> to apply the push/replace history\nstep:</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a data-link-type=\"biblio\" href=\"#biblio-html\" title=\"HTML Standard\">[HTML]</a>:</strong></p>\n    <div class=\"monkeypatch\">\n     <p>To finalize a cross-document navigation given a navigable navigable, history handling behavior\nhistoryHandling, session history entry historyEntry, <span class=\"diff\"> and <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#user-navigation-involvement\" id=\"ref-for-user-navigation-involvement③\">user\nnavigation involvement</a> <var>user involvement</var> (default \"none\")</span>:</p>\n     <ol>\n      <li data-md>\n       <p class=\"assertion\">Assert: this is running on navigable’s traversable navigable’s session history traversal queue.</p>\n      <li data-md>\n       <p>...</p>\n      <li value=\"10\"><span class=\"diff\">Let <var>allow text directive scroll</var> be the result of <a data-link-type=\"dfn\" href=\"#check-if-a-text-directive-can-be-scrolled\" id=\"ref-for-check-if-a-text-directive-can-be-scrolled\">checking if a text directive can be scrolled</a>, given <var>historyEntry</var>’s <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#she-document\" id=\"ref-for-she-document\">document</a>, <var>historyEntry</var>’s <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#she-document-state\" id=\"ref-for-she-document-state\">document state</a>’s <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#document-state-initiator-origin\" id=\"ref-for-document-state-initiator-origin\">initiator origin</a>, and <var>user involvement</var></span> \n      <li data-md>\n       <p>Apply the push/replace history step targetStep to traversable, <span class=\"diff\">with <var>allow\ntext directive scroll</var>.</span></p>\n     </ol>\n    </div>\n   </blockquote>\n   <p>Amend the <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate\" id=\"ref-for-navigate①\">navigate</a> algorithm to pass <var>user involvement</var> to the finalize a\ncross-document navigation steps:</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a data-link-type=\"biblio\" href=\"#biblio-html\" title=\"HTML Standard\">[HTML]</a>:</strong></p>\n    <div class=\"monkeypatch\">\n     <ol>\n      <li data-md>\n       <p>...</p>\n      <li value=\"20\">. In parallel, run these steps:\n      <ol>\n       <li data-md>\n        <p>...</p>\n       <li value=\"9\">. Attempt to populate the history entry’s document for historyEntry, given\nnavigable, \"navigate\", sourceSnapshotParams, targetSnapshotParams, navigationId,\nnavigationParams, cspNavigationType, with allowPOST set to true and completionSteps set to\nthe following step:\n       <ol>\n        <li data-md>\n         <p>Append session history traversal steps to navigable’s traversable to finalize a\ncross-document navigation given navigable, historyHandling, historyEntry, <span class=\"diff\">and <var>userInvolvement</var></span>.</p>\n       </ol>\n      </ol>\n     </ol>\n    </div>\n   </blockquote>\n   <p>Amend the <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate-fragid\" id=\"ref-for-navigate-fragid\">Navigate to a fragment</a> algorithm to take an <var>initiator origin</var> parameter\nand pass the <var>allow text directive scroll</var> flag when scrolling to the fragment:</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a data-link-type=\"biblio\" href=\"#biblio-html\" title=\"HTML Standard\">[HTML]</a>:</strong></p>\n    <div class=\"monkeypatch\">\n     <p>To navigate to a fragment given a navigable navigable, a URL url, a history handling behavior\nhistoryHandling, a user navigation involvement <var>userInvolvement</var>, a serialized state-or-null\nnavigationAPIState, navigation ID navigationId, <span class=\"diff\">an <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsers.html#concept-origin\" id=\"ref-for-concept-origin①\">origin</a> <var>initiator\norigin</var></span>:</p>\n     <ol>\n      <li data-md>\n       <p>Let navigation be <var>navigable</var>’s active window’s navigation API.</p>\n      <li data-md>\n       <p>...</p>\n      <li value=\"14\"> Update document for history step application given navigable’s active document, historyEntry, true, scriptHistoryIndex, and scriptHistoryLength. \n      <li data-md>\n       <p>Update the navigation API entries for a same-document navigation given navigation, historyEntry, and historyHandling.</p>\n      <li data-md>\n       <p><span class=\"diff\">Let <var>allow text directive scroll</var> be the result of <a data-link-type=\"dfn\" href=\"#check-if-a-text-directive-can-be-scrolled\" id=\"ref-for-check-if-a-text-directive-can-be-scrolled①\">checking if a text directive can be scrolled</a>, given <var>navigable</var>’s <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/document-sequences.html#nav-document\" id=\"ref-for-nav-document④\">active document</a>, <var>initiator origin</var>, and <var>userInvolvement</var></span></p>\n      <li data-md>\n       <p>Scroll to the fragment given <var>navigable</var>’s active document<span class=\"diff\">, and <var>allow text\ndirective scroll</var>.</span></p>\n     </ol>\n    </div>\n   </blockquote>\n   <p>Amend the <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate\" id=\"ref-for-navigate②\">navigate</a> algorithm to pass the initiator origin when performing a\nfragment navigation:</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a data-link-type=\"biblio\" href=\"#biblio-html\" title=\"HTML Standard\">[HTML]</a>:</strong></p>\n    <div class=\"monkeypatch\">\n     <ol start=\"10\">\n      <li data-md>\n       <p>If the navigation must be a replace given url and navigable’s active document, then set historyHandling to \"replace\".</p>\n      <li data-md>\n       <p>If all of the following are true:</p>\n       <ul>\n        <li data-md>\n         <p>documentResource is null;</p>\n        <li data-md>\n         <p>response is null;</p>\n        <li data-md>\n         <p>url equals navigable’s active session history entry’s URL with exclude fragments set to true; and</p>\n        <li data-md>\n         <p>url’s fragment is non-null,</p>\n       </ul>\n       <p>then:</p>\n       <ol>\n        <li data-md>\n         <p>Navigate to a fragment given navigable, url, historyHandling, userInvolvement,\nnavigationAPIState, navigationId, <span class=\"diff\">and <var> initiatorOriginSnapshot</var></span></p>\n        <li data-md>\n         <p>Let navigation be <var>navigable</var>’s active window’s navigation API.</p>\n       </ol>\n     </ol>\n    </div>\n   </blockquote>\n   <h4 class=\"heading settled\" data-level=\"3.5.5\" id=\"restricting-scroll-on-load\"><span class=\"secno\">3.5.5. </span><span class=\"content\">Restricting Scroll on Load</span><a class=\"self-link\" href=\"#restricting-scroll-on-load\"></a></h4>\n   <p>This section defines how the <code>force-load-at-top</code> policy is used to prevent all\ntypes of scrolling when loading a new document, including but not limited to\ntext directives.</p>\n   <p class=\"issue\" id=\"issue-de0fed9d\"><a class=\"self-link\" href=\"#issue-de0fed9d\"></a> Need to decide how <code>force-load-at-top</code> interacts with the Navigation API. <a href=\"https://github.com/WICG/scroll-to-text-fragment/issues/242\">[Issue #WICG/scroll-to-text-fragment#242]</a></p>\n   <p>Amend the <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#restore-persisted-state\" id=\"ref-for-restore-persisted-state\">restore persisted state</a> steps to take a new boolean\nparameter which suppresses scroll restoration:</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a data-link-type=\"biblio\" href=\"#biblio-html\" title=\"HTML Standard\">[HTML]</a>:</strong></p>\n    <div class=\"monkeypatch\">\n      To restore persisted state from a session history entry <var>entry</var> <span class=\"diff\">, and boolean <var>suppressScrolling</var></span>: \n     <ol>\n      <li data-md>\n       <p>If entry’s scroll restoration mode is \"auto\", <span class=\"diff\"><var>suppressScrolling</var> is false,</span> and entry’s document’s relevant global object’s navigation API’s suppress\nnormal scroll restoration during ongoing navigation is false, then restore scroll position\ndata given entry.</p>\n      <li data-md>\n       <p>...</p>\n     </ol>\n    </div>\n   </blockquote>\n   <p>Amend the <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#update-document-for-history-step-application\" id=\"ref-for-update-document-for-history-step-application③\">update document for history step application</a> steps\nto check the <code>force-load-at-top</code> policy and avoid scrolling in a new document\nif it’s set.</p>\n   <blockquote>\n    <p><strong>Monkeypatching <a data-link-type=\"biblio\" href=\"#biblio-html\" title=\"HTML Standard\">[HTML]</a>:</strong></p>\n    <div class=\"monkeypatch\">\n     <ol>\n      <li data-md>\n       <p>...</p>\n      <li value=\"4\">Set document’s history object’s length to scriptHistoryLength.\n      <li data-md>\n       <p><span class=\"diff\">Let <var>scrollingBlockedInNewDocument</var> be the result of <a href=\"https://wicg.github.io/document-policy#algo-get-policy-value\">getting the policy\n  value</a> for <code>force-load-at-top</code> for <var>document</var>.</span></p>\n      <li data-md>\n       <p>If documentsEntryChanged is true, then:</p>\n       <ol>\n        <li data-md>\n         <p>Let oldURL be document’s latest entry’s URL.</p>\n        <li data-md>\n         <p>...</p>\n        <li value=\"5\">\n          If documentIsNew is false, then: \n         <ol>\n          <li data-md>\n           <p>Update the navigation API entries for a same-document navigation given navigation,\n  entry, and \"traverse\".</p>\n          <li data-md>\n           <p>Fire an event named popstate...</p>\n          <li data-md>\n           <p>Restore persisted state given entry <span class=\"diff\">and <var>suppressScrolling</var> set to false.</span></p>\n          <li data-md>\n           <p>If oldURL’s fragment is not equal to...</p>\n         </ol>\n        <li data-md>\n         <p>Otherwise,</p>\n         <ol>\n          <li data-md>\n           <p class=\"assertion\">Assert: entriesForNavigationAPI is given.</p>\n          <li data-md>\n           <p>Restore persisted state given entry <span class=\"diff\">and <var>scrollingBlockedInNewDocument</var>.</span></p>\n          <li data-md>\n           <p>Initialize the navigation API entries for a new document given navigation,\n  entriesForNavigationAPI, and entry.</p>\n         </ol>\n       </ol>\n      <li data-md>\n       <p>If documentIsNew is true, then:</p>\n       <ol>\n        <li data-md>\n         <p><span class=\"diff\">If <var>scrollingBlockedInNewDocument</var> is false,</span> try to scroll to\n  the fragment for document.</p>\n        <li data-md>\n         <p>At this point scripts may run for the newly-created document document.</p>\n       </ol>\n      <li data-md>\n       <p>Otherwise, if documentsEntryChanged is false and doNotReactivate is false, then:</p>\n       <ol>\n        <li data-md>\n         <p>...</p>\n       </ol>\n     </ol>\n    </div>\n   </blockquote>\n   <h3 class=\"heading settled\" data-level=\"3.6\" id=\"navigating-to-text-fragment\"><span class=\"secno\">3.6. </span><span class=\"content\">Navigating to a Text Fragment</span><a class=\"self-link\" href=\"#navigating-to-text-fragment\"></a></h3>\n   <div class=\"note\" role=\"note\"> The text fragment specification proposes an amendment to <a href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#scroll-to-fragid\"><cite>HTML</cite> § 7.4.2.3.3 Fragment navigations</a>. In summary, if a <a data-link-type=\"dfn\" href=\"#text-directive\" id=\"ref-for-text-directive①⓪\">text directive</a> is\npresent and a match is found in the page, the text fragment takes precedent over\nthe element fragment as the indicated part. We amend the HTML Document’s\nindicated part processing model to return a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range①①\">range</a>, rather than an <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-element\" id=\"ref-for-concept-element②\">element</a>, that will be scrolled into view. </div>\n   <div class=\"algorithm\" data-algorithm=\"first common ancestor\">\n     To find the <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"first-common-ancestor\">first common ancestor</dfn> of two nodes <var>nodeA</var> and <var>nodeB</var>,\nfollow these steps: \n    <ol class=\"algorithm\">\n     <li data-md>\n      <p>Let <var>commonAncestor</var> be <var>nodeA</var>.</p>\n     <li data-md>\n      <p>While <var>commonAncestor</var> is non-null and is not a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-shadow-including-inclusive-ancestor\" id=\"ref-for-concept-shadow-including-inclusive-ancestor\">shadow-including inclusive\nancestor</a> of <var>nodeB</var>, let <var>commonAncestor</var> be <var>commonAncestor</var>’s <a data-link-type=\"dfn\" href=\"#shadow-including-parent\" id=\"ref-for-shadow-including-parent\">shadow-including parent</a>.</p>\n     <li data-md>\n      <p>Return <var>commonAncestor</var>.</p>\n    </ol>\n   </div>\n   <div class=\"algorithm\" data-algorithm=\"shadow-including parent\">\n     To find the <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"shadow-including-parent\">shadow-including parent</dfn> of <var>node</var> follow these steps: \n    <ol class=\"algorithm\">\n     <li data-md>\n      <p>If <var>node</var> is a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-shadow-root\" id=\"ref-for-concept-shadow-root\">shadow root</a>, return <var>node</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-documentfragment-host\" id=\"ref-for-concept-documentfragment-host\">host</a>.</p>\n     <li data-md>\n      <p>Otherwise, return <var>node</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-tree-parent\" id=\"ref-for-concept-tree-parent①\">parent</a>.</p>\n    </ol>\n   </div>\n   <h4 class=\"heading settled\" data-level=\"3.6.1\" id=\"finding-ranges-in-a-document\"><span class=\"secno\">3.6.1. </span><span class=\"content\">Finding Ranges in a Document</span><a class=\"self-link\" href=\"#finding-ranges-in-a-document\"></a></h4>\n   <div class=\"note\" role=\"note\">\n     This section outlines several algorithms and definitions that specify how to\n  turn a full fragment directive string into a list of <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range①②\">Ranges</a> in the\n  document. \n    <p>At a high level, we take a fragment directive string that looks like this:</p>\n<pre>text=prefix-,foo&amp;unknown&amp;text=bar,baz\n</pre>\n    <p>We break this up into the individual text directives:</p>\n<pre>text=prefix-,foo\ntext=bar,baz\n</pre>\n    <p>For each text directive, we perform a search in the document for the first\n  instance of rendered text that matches the restrictions in the directive.\n  Each search is independent of any others; that is, the result is the same\n  regardless of how many other directives are provided or their match result.</p>\n    <p>If a directive successfully matches to text in the document, it returns a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range①③\">range</a> indicating that match in the document. The <a data-link-type=\"dfn\" href=\"#invoke-text-directives\" id=\"ref-for-invoke-text-directives①\">invoke text directives</a> steps are the high level API provided by this\n  section. These return a <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#list\" id=\"ref-for-list④\">list</a> of <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range①④\">ranges</a> that were matched\n  by the individual directive matching steps, in the order the directives were\n  specified in the fragment directive string.</p>\n    <p>If a directive was not matched, it does not add an item to the returned\n  list.</p>\n   </div>\n   <div class=\"algorithm\" data-algorithm=\"invoke text directives\">\n     To <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"invoke-text-directives\">invoke text directives</dfn>, given as input a <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#list\" id=\"ref-for-list⑤\">list</a> of <a data-link-type=\"dfn\" href=\"#text-directive\" id=\"ref-for-text-directive①①\">text\n  directives</a> <var>text directives</var> and a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-document\" id=\"ref-for-concept-document⑧\">Document</a> <var>document</var>, run these steps: \n    <div class=\"note\" role=\"note\"> This algorithm returns a <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#list\" id=\"ref-for-list⑥\">list</a> of <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range①⑤\">ranges</a> that are to be visually indicated,\n    the first of which will be scrolled into view (if the UA scrolls automatically). </div>\n    <ol class=\"algorithm\">\n     <li data-md>\n      <p>Let <var>ranges</var> be a <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#list\" id=\"ref-for-list⑦\">list</a> of <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range①⑥\">ranges</a>, initially empty.</p>\n     <li data-md>\n      <p><a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#list-iterate\" id=\"ref-for-list-iterate①\">For each</a> <a data-link-type=\"dfn\" href=\"#text-directive\" id=\"ref-for-text-directive①②\">text directive</a> <var>directive</var> of <var>text directives</var>:</p>\n      <ol>\n       <li data-md>\n        <p>If the result of running <a data-link-type=\"dfn\" href=\"#find-a-range-from-a-text-directive\" id=\"ref-for-find-a-range-from-a-text-directive①\">find a range from a text directive</a> given <var>directive</var> and <var>document</var> is non-null, then <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#list-append\" id=\"ref-for-list-append①\">append</a> it to <var>ranges</var>.</p>\n      </ol>\n     <li data-md>\n      <p>Return <var>ranges</var>.</p>\n    </ol>\n   </div>\n   <div class=\"algorithm\" data-algorithm=\"find a range from a text directive\">\n     To <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"find-a-range-from-a-text-directive\">find a range from a text directive</dfn>, given a <a data-link-type=\"dfn\" href=\"#text-directive\" id=\"ref-for-text-directive①③\">text directive</a> <var>parsedValues</var> and <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-document\" id=\"ref-for-concept-document⑨\">Document</a> <var>document</var>, run the\nfollowing steps: \n    <div class=\"note\" role=\"note\">\n      This algorithm takes as input a successfully parsed text directive and a\n  document in which to search. It returns a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range①⑦\">range</a> that points to the first\n  text passage within the document that matches the searched-for text and\n  satisfies the surrounding context. Returns null if no such passage exists. \n     <p><a data-link-type=\"dfn\" href=\"#text-directive-end\" id=\"ref-for-text-directive-end①\">end</a> can be null. If omitted, this is an \"exact\"\n  search and the returned <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range①⑧\">range</a> will contain a string exactly matching <a data-link-type=\"dfn\" href=\"#text-directive-start\" id=\"ref-for-text-directive-start②\">start</a>. If <a data-link-type=\"dfn\" href=\"#text-directive-end\" id=\"ref-for-text-directive-end②\">end</a> is\n  provided, this is a \"range\" search; the returned <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range①⑨\">range</a> will start with <a data-link-type=\"dfn\" href=\"#text-directive-start\" id=\"ref-for-text-directive-start③\">start</a> and end with <a data-link-type=\"dfn\" href=\"#text-directive-end\" id=\"ref-for-text-directive-end③\">end</a>. In the normative text below, we’ll call a\n  text passage that matches the provided <a data-link-type=\"dfn\" href=\"#text-directive-start\" id=\"ref-for-text-directive-start④\">start</a> and <a data-link-type=\"dfn\" href=\"#text-directive-end\" id=\"ref-for-text-directive-end④\">end</a>, regardless of which mode we’re in, the\n  \"matching text\".</p>\n     <p>Either or both of <a data-link-type=\"dfn\" href=\"#text-directive-prefix\" id=\"ref-for-text-directive-prefix①\">prefix</a> and <a data-link-type=\"dfn\" href=\"#text-directive-suffix\" id=\"ref-for-text-directive-suffix①\">suffix</a> can be null, in which case context on that\n  side of a match is not checked. E.g. If <a data-link-type=\"dfn\" href=\"#text-directive-prefix\" id=\"ref-for-text-directive-prefix②\">prefix</a> is\n  null, text is matched without any requirement on what text precedes it.</p>\n    </div>\n    <div class=\"note\" role=\"note\">\n      While the matching text and its prefix/suffix can span across\n  block-boundaries, the individual parameters to these steps cannot. That is,\n  each of <a data-link-type=\"dfn\" href=\"#text-directive-prefix\" id=\"ref-for-text-directive-prefix③\">prefix</a>, <a data-link-type=\"dfn\" href=\"#text-directive-start\" id=\"ref-for-text-directive-start⑤\">start</a>, <a data-link-type=\"dfn\" href=\"#text-directive-end\" id=\"ref-for-text-directive-end⑤\">end</a>, and <a data-link-type=\"dfn\" href=\"#text-directive-suffix\" id=\"ref-for-text-directive-suffix②\">suffix</a> will only\n  match text within a single block. \n     <div class=\"example\" id=\"example-73638554\">\n      <a class=\"self-link\" href=\"#example-73638554\"></a> \n<pre>:~:text=The quick,lazy dog</pre>\n       will fail to match in \n<pre>&lt;div>The&lt;div> &lt;/div>quick brown fox&lt;/div>\n&lt;div>jumped over the lazy dog&lt;/div>\n</pre>\n      <p>because the starting string \"The quick\" does not appear within a single,\n    uninterrupted block. The instance of \"The quick\" in the document has a\n    block element between \"The\" and \"quick\".</p>\n      <p>It does, however, match in this example:</p>\n<pre>&lt;div>The quick brown fox&lt;/div>\n&lt;div>jumped over the lazy dog&lt;/div>\n</pre>\n     </div>\n    </div>\n    <ol class=\"algorithm\">\n     <li data-md>\n      <p>Let <var>searchRange</var> be a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range②⓪\">range</a> with <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start\" id=\"ref-for-concept-range-start\">start</a> (<var>document</var>, 0) and <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-end\" id=\"ref-for-concept-range-end\">end</a> (<var>document</var>, <var>document</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-node-length\" id=\"ref-for-concept-node-length\">length</a>)</p>\n     <li data-md>\n      <p>While <var>searchRange</var> is not <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#range-collapsed\" id=\"ref-for-range-collapsed\">collapsed</a>:</p>\n      <ol>\n       <li data-md>\n        <p>Let <var>potentialMatch</var> be null.</p>\n       <li data-md>\n        <p>If <var>parsedValues</var>’s <a data-link-type=\"dfn\" href=\"#text-directive-prefix\" id=\"ref-for-text-directive-prefix④\">prefix</a> is not null:</p>\n        <ol>\n         <li data-md>\n          <p>Let <var>prefixMatch</var> be the the result of running the <a data-link-type=\"dfn\" href=\"#find-a-string-in-range\" id=\"ref-for-find-a-string-in-range\">find a string\nin range</a> steps with <var>query</var> <var>parsedValues</var>’s <a data-link-type=\"dfn\" href=\"#text-directive-prefix\" id=\"ref-for-text-directive-prefix⑤\">prefix</a>, <var>searchRange</var> <var>searchRange</var>, <var>wordStartBounded</var> true and <var>wordEndBounded</var> false.</p>\n         <li data-md>\n          <p>If <var>prefixMatch</var> is null, return null.</p>\n         <li data-md>\n          <p>Set <var>searchRange</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start\" id=\"ref-for-concept-range-start①\">start</a> to the first <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-bp\" id=\"ref-for-concept-range-bp\">boundary point</a> <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-bp-after\" id=\"ref-for-concept-range-bp-after\">after</a> <var>prefixMatch</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start\" id=\"ref-for-concept-range-start②\">start</a></p>\n         <li data-md>\n          <p>Let <var>matchRange</var> be a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range②①\">range</a> whose <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start\" id=\"ref-for-concept-range-start③\">start</a> is <var>prefixMatch</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-end\" id=\"ref-for-concept-range-end①\">end</a> and <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-end\" id=\"ref-for-concept-range-end②\">end</a> is <var>searchRange</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-end\" id=\"ref-for-concept-range-end③\">end</a>.</p>\n         <li data-md>\n          <p>Advance <var>matchRange</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start\" id=\"ref-for-concept-range-start④\">start</a> to the <a data-link-type=\"dfn\" href=\"#next-non-whitespace-position\" id=\"ref-for-next-non-whitespace-position\">next non-whitespace position</a>.</p>\n         <li data-md>\n          <p>If <var>matchRange</var> is <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#range-collapsed\" id=\"ref-for-range-collapsed①\">collapsed</a> return null.</p>\n          <div class=\"note\" role=\"note\"> This can happen if <var>prefixMatch</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-end\" id=\"ref-for-concept-range-end④\">end</a> or its subsequent\n  non-whitespace position is at the end of the document. </div>\n         <li data-md>\n          <p><a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#assert\" id=\"ref-for-assert③\">Assert</a>: <var>matchRange</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start-node\" id=\"ref-for-concept-range-start-node②\">start node</a> is a <code class=\"idl\"><a data-link-type=\"idl\" href=\"https://dom.spec.whatwg.org/#text\" id=\"ref-for-text\">Text</a></code> node.</p>\n          <div class=\"note\" role=\"note\"> <var>matchRange</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start\" id=\"ref-for-concept-range-start⑤\">start</a> now points to the next\n  non-whitespace text data following a matched prefix. </div>\n         <li data-md>\n          <p>Let <var>mustEndAtWordBoundary</var> be true if <var>parsedValues</var>’s <a data-link-type=\"dfn\" href=\"#text-directive-end\" id=\"ref-for-text-directive-end⑥\">end</a> is non-null or <var>parsedValues</var>’s <a data-link-type=\"dfn\" href=\"#text-directive-suffix\" id=\"ref-for-text-directive-suffix③\">suffix</a> is null, false\notherwise.</p>\n         <li data-md>\n          <p>Set <var>potentialMatch</var> to the result of running the <a data-link-type=\"dfn\" href=\"#find-a-string-in-range\" id=\"ref-for-find-a-string-in-range①\">find a string in\nrange</a> steps with <var>query</var> <var>parsedValues</var>’s <a data-link-type=\"dfn\" href=\"#text-directive-start\" id=\"ref-for-text-directive-start⑥\">start</a>, <var>searchRange</var> <var>matchRange</var>, <var>wordStartBounded</var> false, and <var>wordEndBounded</var> <var>mustEndAtWordBoundary</var>.</p>\n         <li data-md>\n          <p>If <var>potentialMatch</var> is null, return null.</p>\n         <li data-md>\n          <p>If <var>potentialMatch</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start\" id=\"ref-for-concept-range-start⑥\">start</a> is not <var>matchRange</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start\" id=\"ref-for-concept-range-start⑦\">start</a>, then <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#iteration-continue\" id=\"ref-for-iteration-continue①\">continue</a>.</p>\n          <div class=\"note\" role=\"note\"> In this case, we found a prefix but it was followed by something\n  other than a matching text so we’ll continue searching for the\n  next instance of <a data-link-type=\"dfn\" href=\"#text-directive-prefix\" id=\"ref-for-text-directive-prefix⑥\">prefix</a>. </div>\n        </ol>\n       <li data-md>\n        <p>Otherwise:</p>\n        <ol>\n         <li data-md>\n          <p>Let <var>mustEndAtWordBoundary</var> be true if <var>parsedValues</var>’s <a data-link-type=\"dfn\" href=\"#text-directive-end\" id=\"ref-for-text-directive-end⑦\">end</a> is non-null or <var>parsedValues</var>’s <a data-link-type=\"dfn\" href=\"#text-directive-suffix\" id=\"ref-for-text-directive-suffix④\">suffix</a> is null, false\notherwise.</p>\n         <li data-md>\n          <p>Set <var>potentialMatch</var> to the result of running the <a data-link-type=\"dfn\" href=\"#find-a-string-in-range\" id=\"ref-for-find-a-string-in-range②\">find a string in\nrange</a> steps with <var>query</var> <var>parsedValues</var>’s <a data-link-type=\"dfn\" href=\"#text-directive-start\" id=\"ref-for-text-directive-start⑦\">start</a>, <var>searchRange</var> <var>searchRange</var>, <var>wordStartBounded</var> true, and <var>wordEndBounded</var> <var>mustEndAtWordBoundary</var>.</p>\n         <li data-md>\n          <p>If <var>potentialMatch</var> is null, return null.</p>\n         <li data-md>\n          <p>Set <var>searchRange</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start\" id=\"ref-for-concept-range-start⑧\">start</a> to the first <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-bp\" id=\"ref-for-concept-range-bp①\">boundary point</a> <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-bp-after\" id=\"ref-for-concept-range-bp-after①\">after</a> <var>potentialMatch</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start\" id=\"ref-for-concept-range-start⑨\">start</a></p>\n        </ol>\n       <li data-md>\n        <p>Let <var>rangeEndSearchRange</var> be a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range②②\">range</a> whose <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start\" id=\"ref-for-concept-range-start①⓪\">start</a> is <var>potentialMatch</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-end\" id=\"ref-for-concept-range-end⑤\">end</a> and whose <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-end\" id=\"ref-for-concept-range-end⑥\">end</a> is <var>searchRange</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-end\" id=\"ref-for-concept-range-end⑦\">end</a>.</p>\n       <li data-md>\n        <p>While <var>rangeEndSearchRange</var> is not <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#range-collapsed\" id=\"ref-for-range-collapsed②\">collapsed</a>:</p>\n        <ol>\n         <li data-md>\n          <p>If <var>parsedValues</var>’s <a data-link-type=\"dfn\" href=\"#text-directive-end\" id=\"ref-for-text-directive-end⑧\">end</a> item is\nnon-null, then:</p>\n          <ol>\n           <li data-md>\n            <p>Let <var>mustEndAtWordBoundary</var> be true if <var>parsedValues</var>’s <a data-link-type=\"dfn\" href=\"#text-directive-suffix\" id=\"ref-for-text-directive-suffix⑤\">suffix</a> is null, false otherwise.</p>\n           <li data-md>\n            <p>Let <var>endMatch</var> be the result of running the <a data-link-type=\"dfn\" href=\"#find-a-string-in-range\" id=\"ref-for-find-a-string-in-range③\">find a string\nin range</a> steps with <var>query</var> <var>parsedValues</var>’s <a data-link-type=\"dfn\" href=\"#text-directive-end\" id=\"ref-for-text-directive-end⑨\">end</a>, <var>searchRange</var> <var>rangeEndSearchRange</var>, <var>wordStartBounded</var> true, and <var>wordEndBounded</var> <var>mustEndAtWordBoundary</var>.</p>\n           <li data-md>\n            <p>If <var>endMatch</var> is null then return null.</p>\n           <li data-md>\n            <p>Set <var>potentialMatch</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-end\" id=\"ref-for-concept-range-end⑧\">end</a> to <var>endMatch</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-end\" id=\"ref-for-concept-range-end⑨\">end</a>.</p>\n          </ol>\n         <li data-md>\n          <p><a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#assert\" id=\"ref-for-assert④\">Assert</a>: <var>potentialMatch</var> is non-null, not <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#range-collapsed\" id=\"ref-for-range-collapsed③\">collapsed</a> and\nrepresents a range exactly containing an instance of matching text.</p>\n         <li data-md>\n          <p>If <var>parsedValues</var>’s <a data-link-type=\"dfn\" href=\"#text-directive-suffix\" id=\"ref-for-text-directive-suffix⑥\">suffix</a> is null, return <var>potentialMatch</var>.</p>\n         <li data-md>\n          <p>Let <var>suffixRange</var> be a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range②③\">range</a> with <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start\" id=\"ref-for-concept-range-start①①\">start</a> equal to <var>potentialMatch</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-end\" id=\"ref-for-concept-range-end①⓪\">end</a> and <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-end\" id=\"ref-for-concept-range-end①①\">end</a> equal to <var>searchRange</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-end\" id=\"ref-for-concept-range-end①②\">end</a>.</p>\n         <li data-md>\n          <p>Advance <var>suffixRange</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start\" id=\"ref-for-concept-range-start①②\">start</a> to the <a data-link-type=\"dfn\" href=\"#next-non-whitespace-position\" id=\"ref-for-next-non-whitespace-position①\">next non-whitespace\nposition</a>.</p>\n         <li data-md>\n          <p>Let <var>suffixMatch</var> be result of running the <a data-link-type=\"dfn\" href=\"#find-a-string-in-range\" id=\"ref-for-find-a-string-in-range④\">find a string in range</a> steps with <var>query</var> <var>parsedValues</var>’s <a data-link-type=\"dfn\" href=\"#text-directive-suffix\" id=\"ref-for-text-directive-suffix⑦\">suffix</a>, <var>searchRange</var> <var>suffixRange</var>, <var>wordStartBounded</var> false, and <var>wordEndBounded</var> true.</p>\n         <li data-md>\n          <p>If <var>suffixMatch</var> is null then return null.</p>\n          <div class=\"note\" role=\"note\"> If the suffix doesn’t appear in the remaining text of the document,\n  there’s no possible way to make a match. </div>\n         <li data-md>\n          <p>If <var>suffixMatch</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start\" id=\"ref-for-concept-range-start①③\">start</a> is <var>suffixRange</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start\" id=\"ref-for-concept-range-start①④\">start</a>,\nreturn <var>potentialMatch</var>.</p>\n         <li data-md>\n          <p>If <var>parsedValues</var>’s <a data-link-type=\"dfn\" href=\"#text-directive-end\" id=\"ref-for-text-directive-end①⓪\">end</a> item is null\nthen <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#iteration-break\" id=\"ref-for-iteration-break\">break</a>;</p>\n          <div class=\"note\" role=\"note\"> If this is an exact match and the suffix doesn’t match,\n  start searching for the next range start by breaking out\n  of this loop without <var>rangeEndSearchRange</var> being collapsed.\n  If we’re looking for a range match, we’ll continue iterating\n  this inner loop since the range start will already be correct. </div>\n         <li data-md>\n          <p>Set <var>rangeEndSearchRange</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start\" id=\"ref-for-concept-range-start①⑤\">start</a> to <var>potentialMatch</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-end\" id=\"ref-for-concept-range-end①③\">end</a>.</p>\n          <div class=\"note\" role=\"note\"> Otherwise, it is possible that we found the correct range\n  start, but not the correct range end. Continue the inner\n  loop to keep searching for another matching instance of\n  rangeEnd. </div>\n        </ol>\n       <li data-md>\n        <p>If <var>rangeEndSearchRange</var> is <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#range-collapsed\" id=\"ref-for-range-collapsed④\">collapsed</a> then:</p>\n        <ol>\n         <li data-md>\n          <p><a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#assert\" id=\"ref-for-assert⑤\">Assert</a>: <var>parsedValues</var>’s <a data-link-type=\"dfn\" href=\"#text-directive-end\" id=\"ref-for-text-directive-end①①\">end</a> item is non-null</p>\n         <li data-md>\n          <p>Return null</p>\n          <div class=\"note\" role=\"note\"> This can only happen for range matches due to the <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#iteration-break\" id=\"ref-for-iteration-break①\">break</a> for exact matches in step 9 of the\n    above loop. If we couldn’t find a valid rangeEnd+suffix\n    pair anywhere in the doc then there’s no possible way to\n    make a match. </div>\n        </ol>\n      </ol>\n     <li data-md>\n      <p>Return null</p>\n    </ol>\n   </div>\n   <details class=\"wpt-tests-block\" dir=\"ltr\" lang=\"en\" open>\n    <summary>Tests</summary>\n    <ul class=\"wpt-tests-list\">\n     <li class=\"wpt-test\"><a class=\"wpt-name\" href=\"https://wpt.fyi/results/scroll-to-text-fragment/find-range-from-text-directive.html\" title=\"scroll-to-text-fragment/find-range-from-text-directive.html\">find-range-from-text-directive.html</a> <a class=\"wpt-live\" href=\"http://wpt.live/scroll-to-text-fragment/find-range-from-text-directive.html\"><small>(live test)</small></a> <a class=\"wpt-source\" href=\"https://github.com/web-platform-tests/wpt/blob/master/scroll-to-text-fragment/find-range-from-text-directive.html\"><small>(source)</small></a>\n    </ul>\n   </details>\n   <div class=\"algorithm\" data-algorithm=\"advance range start to next non-whitespace position\">\n     To advance a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range②④\">range</a> <var>range</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start\" id=\"ref-for-concept-range-start①⑥\">start</a> to the <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-lt=\"next non-whitespace position\" data-noexport id=\"next-non-whitespace-position\">next\nnon-whitespace position</dfn> follow the steps: \n    <ol class=\"algorithm\">\n     <li data-md>\n      <p>While <var>range</var> is not collapsed:</p>\n      <ol>\n       <li data-md>\n        <p>Let <var>node</var> be <var>range</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start-node\" id=\"ref-for-concept-range-start-node③\">start node</a>.</p>\n       <li data-md>\n        <p>Let <var>offset</var> be <var>range</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start-offset\" id=\"ref-for-concept-range-start-offset\">start offset</a>.</p>\n       <li data-md>\n        <p>If <var>node</var> is part of a <a data-link-type=\"dfn\" href=\"#non-searchable-subtree\" id=\"ref-for-non-searchable-subtree\">non-searchable subtree</a> or if <var>node</var> is\nnot a <a data-link-type=\"dfn\" href=\"#visible-text-node\" id=\"ref-for-visible-text-node\">visible text node</a> or if <var>offset</var> is equal to <var>node</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-node-length\" id=\"ref-for-concept-node-length①\">length</a> then:</p>\n        <ol>\n         <li data-md>\n          <p>Set <var>range</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start-node\" id=\"ref-for-concept-range-start-node④\">start node</a> to the next node, in <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-shadow-including-tree-order\" id=\"ref-for-concept-shadow-including-tree-order\">shadow-including tree order</a>.</p>\n         <li data-md>\n          <p>Set <var>range</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start-offset\" id=\"ref-for-concept-range-start-offset①\">start offset</a> to 0.</p>\n         <li data-md>\n          <p><a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#iteration-continue\" id=\"ref-for-iteration-continue②\">Continue</a>.</p>\n        </ol>\n       <li data-md>\n        <p>If the <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-cd-substring\" id=\"ref-for-concept-cd-substring\">substring data</a> of <var>node</var> at offset <var>offset</var> and count 6 is equal to the string \"&amp;nbsp;\" then:</p>\n        <ol>\n         <li data-md>\n          <p>Add 6 to <var>range</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start-offset\" id=\"ref-for-concept-range-start-offset②\">start offset</a>.</p>\n        </ol>\n       <li data-md>\n        <p>Otherwise, if the <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-cd-substring\" id=\"ref-for-concept-cd-substring①\">substring data</a> of <var>node</var> at offset <var>offset</var> and count 5 is equal to the string \"&amp;nbsp\" then:</p>\n        <ol>\n         <li data-md>\n          <p>Add 5 to <var>range</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start-offset\" id=\"ref-for-concept-range-start-offset③\">start offset</a>.</p>\n        </ol>\n       <li data-md>\n        <p>Otherwise:</p>\n        <ol>\n         <li data-md>\n          <p>Let <var>cp</var> be the <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#code-point\" id=\"ref-for-code-point\">code point</a> at the <var>offset</var> index in <var>node</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-cd-data\" id=\"ref-for-concept-cd-data\">data</a>.</p>\n         <li data-md>\n          <p>If <var>cp</var> does not have the <a href=\"http://www.unicode.org/reports/tr44/#White_Space\">White_Space</a> property set, return.</p>\n         <li data-md>\n          <p>Add 1 to <var>range</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start-offset\" id=\"ref-for-concept-range-start-offset④\">start offset</a>.</p>\n        </ol>\n      </ol>\n    </ol>\n   </div>\n   <div class=\"algorithm\" data-algorithm=\"find a string in a range\">\n     To <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"find-a-string-in-range\">find a string in range</dfn> given a <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#string\" id=\"ref-for-string⑤\">string</a> <var>query</var>, a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range②⑤\">range</a> <var>searchRange</var>, and booleans <var>wordStartBounded</var> and <var>wordEndBounded</var>,\nrun these steps: \n    <div class=\"note\" role=\"note\"> This algorithm will return a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range②⑥\">range</a> that represents the first instance of\n  the <var>query</var> text that is fully contained within <var>searchRange</var>, optionally\n  restricting itself to matches that start and/or end at word boundaries (see <a href=\"#word-boundaries\">§ 3.6.2 Word Boundaries</a>). Returns null if none is found. </div>\n    <div class=\"note\" role=\"note\">\n     <p> The basic premise of this algorithm is to walk all searchable text nodes\n    within a block, collecting them into a list. The list is then concatenated\n    into a single string in which we can search, using the node list to\n    determine offsets with a node so we can return a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range②⑦\">range</a>. </p>\n     <p> Collection breaks when we hit a block node, e.g. searching over this tree: </p>\n<pre>&lt;div>\n  a&lt;em>b&lt;/em>c&lt;div>d&lt;/div>e\n&lt;/div>\n</pre>\n     <p></p>\n     <p>Will perform a search on \"abc\", then on \"d\", then on \"e\".</p>\n     <p>Thus, <var>query</var> will only match text that is continuous (i.e. uninterrupted by\n  a block-level container) within a single block-level container.</p>\n    </div>\n    <ol class=\"algorithm\">\n     <li data-md>\n      <p>While <var>searchRange</var> is not <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#range-collapsed\" id=\"ref-for-range-collapsed⑤\">collapsed</a>:</p>\n      <ol>\n       <li data-md>\n        <p>Let <var>curNode</var> be <var>searchRange</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start-node\" id=\"ref-for-concept-range-start-node⑤\">start node</a>.</p>\n       <li data-md>\n        <p>If <var>curNode</var> is part of a <a data-link-type=\"dfn\" href=\"#non-searchable-subtree\" id=\"ref-for-non-searchable-subtree①\">non-searchable subtree</a>:</p>\n        <ol>\n         <li data-md>\n          <p>Set <var>searchRange</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start-node\" id=\"ref-for-concept-range-start-node⑥\">start node</a> to the next node, in <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-shadow-including-tree-order\" id=\"ref-for-concept-shadow-including-tree-order①\">shadow-including tree order</a>, that isn’t a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-shadow-including-descendant\" id=\"ref-for-concept-shadow-including-descendant\">shadow-including\ndescendant</a> of <var>curNode</var>.</p>\n         <li data-md>\n          <p>Set <var>searchRange</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start-offset\" id=\"ref-for-concept-range-start-offset⑤\">start offset</a> to 0.</p>\n         <li data-md>\n          <p><a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#iteration-continue\" id=\"ref-for-iteration-continue③\">Continue</a>.</p>\n        </ol>\n       <li data-md>\n        <p>If <var>curNode</var> is not a <a data-link-type=\"dfn\" href=\"#visible-text-node\" id=\"ref-for-visible-text-node①\">visible text node</a>:</p>\n        <ol>\n         <li data-md>\n          <p>Set <var>searchRange</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start-node\" id=\"ref-for-concept-range-start-node⑦\">start node</a> to the next node, in <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-shadow-including-tree-order\" id=\"ref-for-concept-shadow-including-tree-order②\">shadow-including tree order</a>, that is not a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-doctype\" id=\"ref-for-concept-doctype\">doctype</a>.</p>\n         <li data-md>\n          <p>Set <var>searchRange</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start-offset\" id=\"ref-for-concept-range-start-offset⑥\">start offset</a> to 0.</p>\n         <li data-md>\n          <p><a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#iteration-continue\" id=\"ref-for-iteration-continue④\">Continue</a>.</p>\n        </ol>\n       <li data-md>\n        <p>Let <var>blockAncestor</var> be the <a data-link-type=\"dfn\" href=\"#nearest-block-ancestor\" id=\"ref-for-nearest-block-ancestor\">nearest block ancestor</a> of <var>curNode</var>.</p>\n       <li data-md>\n        <p>Let <var>textNodeList</var> be a <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#list\" id=\"ref-for-list⑧\">list</a> of <code class=\"idl\"><a data-link-type=\"idl\" href=\"https://dom.spec.whatwg.org/#text\" id=\"ref-for-text①\">Text</a></code> nodes,\ninitially empty.</p>\n       <li data-md>\n        <p>While <var>curNode</var> is a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-shadow-including-descendant\" id=\"ref-for-concept-shadow-including-descendant①\">shadow-including descendant</a> of <var>blockAncestor</var> and the position of the <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-bp\" id=\"ref-for-concept-range-bp②\">boundary point</a> (<var>curNode</var>, 0) is not <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-bp-after\" id=\"ref-for-concept-range-bp-after②\">after</a> <var>searchRange</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-end\" id=\"ref-for-concept-range-end①④\">end</a>:</p>\n        <ol>\n         <li data-md>\n          <p>If <var>curNode</var> <a data-link-type=\"dfn\" href=\"#has-block-level-display\" id=\"ref-for-has-block-level-display\">has block-level display</a> then <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#iteration-break\" id=\"ref-for-iteration-break②\">break</a>.</p>\n         <li data-md>\n          <p>If <var>curNode</var> is <a data-link-type=\"dfn\" href=\"#search-invisible\" id=\"ref-for-search-invisible\">search invisible</a>:</p>\n          <ol>\n           <li data-md>\n            <p>Set <var>curNode</var> to the next node, in <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-shadow-including-tree-order\" id=\"ref-for-concept-shadow-including-tree-order③\">shadow-including tree\norder</a>, that isn’t a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-shadow-including-descendant\" id=\"ref-for-concept-shadow-including-descendant②\">shadow-including descendant</a> of <var>curNode</var>.</p>\n           <li data-md>\n            <p><a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#iteration-continue\" id=\"ref-for-iteration-continue⑤\">Continue</a>.</p>\n          </ol>\n         <li data-md>\n          <p>If <var>curNode</var> is a <a data-link-type=\"dfn\" href=\"#visible-text-node\" id=\"ref-for-visible-text-node②\">visible text node</a> then append it to <var>textNodeList</var>.</p>\n         <li data-md>\n          <p>Set <var>curNode</var> to the next node in <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-shadow-including-tree-order\" id=\"ref-for-concept-shadow-including-tree-order④\">shadow-including tree order</a>.</p>\n        </ol>\n       <li data-md>\n        <p>Run the <a data-link-type=\"dfn\" href=\"#find-a-range-from-a-node-list\" id=\"ref-for-find-a-range-from-a-node-list\">find a range from a node list</a> steps given <var>query</var>, <var>searchRange</var>, <var>textNodeList</var>, <var>wordStartBounded</var> and <var>wordEndBounded</var> as input. If the resulting <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range②⑧\">range</a> is not null, then return it.</p>\n       <li data-md>\n        <p>If <var>curNode</var> is null, then <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#iteration-break\" id=\"ref-for-iteration-break③\">break</a>.</p>\n       <li data-md>\n        <p><a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#assert\" id=\"ref-for-assert⑥\">Assert</a>: <var>curNode</var> <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-tree-following\" id=\"ref-for-concept-tree-following\">follows</a> <var>searchRange</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start-node\" id=\"ref-for-concept-range-start-node⑧\">start node</a>.</p>\n       <li data-md>\n        <p>Set <var>searchRange</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start\" id=\"ref-for-concept-range-start①⑦\">start</a> to the <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-bp\" id=\"ref-for-concept-range-bp③\">boundary point</a> (<var>curNode</var>,\n0).</p>\n      </ol>\n     <li data-md>\n      <p>Return null.</p>\n    </ol>\n   </div>\n   <p>A node is <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"search-invisible\">search invisible</dfn> if it is an <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-element\" id=\"ref-for-concept-element③\">element</a> in the <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#html-namespace\" id=\"ref-for-html-namespace\">HTML\nnamespace</a> and meets any of the following conditions:</p>\n   <ol>\n    <li data-md>\n     <p>The <a data-link-type=\"dfn\" href=\"https://drafts.csswg.org/css-cascade-5/#computed-value\" id=\"ref-for-computed-value\">computed value</a> of its <a class=\"property css\" data-link-type=\"property\" href=\"https://drafts.csswg.org/css-display-4/#propdef-display\" id=\"ref-for-propdef-display\">display</a> property is <a class=\"css\" data-link-type=\"maybe\" href=\"https://drafts.csswg.org/css-display-4/#valdef-display-none\" id=\"ref-for-valdef-display-none\">none</a>.</p>\n    <li data-md>\n     <p>If the node <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/parsing.html#serializes-as-void\" id=\"ref-for-serializes-as-void\">serializes as void</a>.</p>\n    <li data-md>\n     <p>Is any of the following types: <code class=\"idl\"><a data-link-type=\"idl\" href=\"https://html.spec.whatwg.org/multipage/iframe-embed-object.html#htmliframeelement\" id=\"ref-for-htmliframeelement\">HTMLIFrameElement</a></code>, <code class=\"idl\"><a data-link-type=\"idl\" href=\"https://html.spec.whatwg.org/multipage/embedded-content.html#htmlimageelement\" id=\"ref-for-htmlimageelement\">HTMLImageElement</a></code>, <code class=\"idl\"><a data-link-type=\"idl\" href=\"https://html.spec.whatwg.org/multipage/form-elements.html#htmlmeterelement\" id=\"ref-for-htmlmeterelement\">HTMLMeterElement</a></code>, <code class=\"idl\"><a data-link-type=\"idl\" href=\"https://html.spec.whatwg.org/multipage/iframe-embed-object.html#htmlobjectelement\" id=\"ref-for-htmlobjectelement\">HTMLObjectElement</a></code>, <code class=\"idl\"><a data-link-type=\"idl\" href=\"https://html.spec.whatwg.org/multipage/form-elements.html#htmlprogresselement\" id=\"ref-for-htmlprogresselement\">HTMLProgressElement</a></code>, <code class=\"idl\"><a data-link-type=\"idl\" href=\"https://html.spec.whatwg.org/multipage/semantics.html#htmlstyleelement\" id=\"ref-for-htmlstyleelement\">HTMLStyleElement</a></code>, <code class=\"idl\"><a data-link-type=\"idl\" href=\"https://html.spec.whatwg.org/multipage/scripting.html#htmlscriptelement\" id=\"ref-for-htmlscriptelement\">HTMLScriptElement</a></code>, <code class=\"idl\"><a data-link-type=\"idl\" href=\"https://html.spec.whatwg.org/multipage/media.html#htmlvideoelement\" id=\"ref-for-htmlvideoelement\">HTMLVideoElement</a></code>, <code class=\"idl\"><a data-link-type=\"idl\" href=\"https://html.spec.whatwg.org/multipage/media.html#htmlaudioelement\" id=\"ref-for-htmlaudioelement\">HTMLAudioElement</a></code></p>\n    <li data-md>\n     <p>Is a <code><a data-link-type=\"element\" href=\"https://html.spec.whatwg.org/multipage/form-elements.html#the-select-element\" id=\"ref-for-the-select-element\">select</a></code> element whose <code><a data-link-type=\"element-sub\" href=\"https://html.spec.whatwg.org/multipage/form-elements.html#attr-select-multiple\" id=\"ref-for-attr-select-multiple\">multiple</a></code> content attribute is absent.</p>\n   </ol>\n   <p>A node is part of a <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"non-searchable-subtree\">non-searchable subtree</dfn> if it is or has a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-shadow-including-ancestor\" id=\"ref-for-concept-shadow-including-ancestor\">shadow-including ancestor</a> that is <a data-link-type=\"dfn\" href=\"#search-invisible\" id=\"ref-for-search-invisible①\">search invisible</a>.</p>\n   <p>A node is a <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"visible-text-node\">visible text node</dfn> if it is a <code class=\"idl\"><a data-link-type=\"idl\" href=\"https://dom.spec.whatwg.org/#text\" id=\"ref-for-text②\">Text</a></code> node, the <a data-link-type=\"dfn\" href=\"https://drafts.csswg.org/css-cascade-5/#computed-value\" id=\"ref-for-computed-value①\">computed value</a> of its <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#parent-element\" id=\"ref-for-parent-element\">parent element</a>'s <a class=\"property css\" data-link-type=\"property\" href=\"https://drafts.csswg.org/css-display-4/#propdef-visibility\" id=\"ref-for-propdef-visibility\">visibility</a> property is <a class=\"css\" data-link-type=\"maybe\" href=\"https://drafts.csswg.org/css-display-4/#valdef-visibility-visible\" id=\"ref-for-valdef-visibility-visible\">visible</a>, and it is <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/rendering.html#being-rendered\" id=\"ref-for-being-rendered\">being rendered</a>.</p>\n   <p>A node <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"has-block-level-display\">has block-level display</dfn> if it is an <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-element\" id=\"ref-for-concept-element④\">element</a> and the <a data-link-type=\"dfn\" href=\"https://drafts.csswg.org/css-cascade-5/#computed-value\" id=\"ref-for-computed-value②\">computed value</a> of its <a class=\"property css\" data-link-type=\"property\" href=\"https://drafts.csswg.org/css-display-4/#propdef-display\" id=\"ref-for-propdef-display①\">display</a> property is any of <a class=\"css\" data-link-type=\"maybe\" href=\"https://drafts.csswg.org/css-display-4/#valdef-display-block\" id=\"ref-for-valdef-display-block\">block</a>, <a class=\"css\" data-link-type=\"maybe\" href=\"https://drafts.csswg.org/css-display-4/#valdef-display-table\" id=\"ref-for-valdef-display-table\">table</a>, <a class=\"css\" data-link-type=\"maybe\" href=\"https://drafts.csswg.org/css-display-4/#valdef-display-flow-root\" id=\"ref-for-valdef-display-flow-root\">flow-root</a>, <a class=\"css\" data-link-type=\"maybe\" href=\"https://drafts.csswg.org/css-display-3/#valdef-display-grid\" id=\"ref-for-valdef-display-grid\">grid</a>, <a class=\"css\" data-link-type=\"maybe\" href=\"https://drafts.csswg.org/css-display-3/#valdef-display-flex\" id=\"ref-for-valdef-display-flex\">flex</a>, <a class=\"css\" data-link-type=\"maybe\" href=\"https://drafts.csswg.org/css-display-4/#valdef-display-list-item\" id=\"ref-for-valdef-display-list-item\">list-item</a>.</p>\n   <div class=\"algorithm\" data-algorithm=\"nearest block ancestor\">\n     To find the <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"nearest-block-ancestor\">nearest block ancestor</dfn> of a <var>node</var> follow the steps: \n    <ol class=\"algorithm\">\n     <li data-md>\n      <p>Let <var>curNode</var> be <var>node</var>.</p>\n     <li data-md>\n      <p>While <var>curNode</var> is non-null</p>\n      <ol>\n       <li data-md>\n        <p>If <var>curNode</var> is not a <code class=\"idl\"><a data-link-type=\"idl\" href=\"https://dom.spec.whatwg.org/#text\" id=\"ref-for-text③\">Text</a></code> node and it <a data-link-type=\"dfn\" href=\"#has-block-level-display\" id=\"ref-for-has-block-level-display①\">has block-level display</a> then\nreturn <var>curNode</var>.</p>\n       <li data-md>\n        <p>Otherwise, set <var>curNode</var> to <var>curNode</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-tree-parent\" id=\"ref-for-concept-tree-parent②\">parent</a>.</p>\n      </ol>\n     <li data-md>\n      <p>Return <var>node</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-node-document\" id=\"ref-for-concept-node-document\">node document</a>'s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#document-element\" id=\"ref-for-document-element\">document element</a>.</p>\n    </ol>\n   </div>\n   <div class=\"algorithm\" data-algorithm=\"range from node list\">\n     To <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"find-a-range-from-a-node-list\">find a range from a node list</dfn> given a search string <var>queryString</var>,\na <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range②⑨\">range</a> <var>searchRange</var>, a <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#list\" id=\"ref-for-list⑨\">list</a> of <code class=\"idl\"><a data-link-type=\"idl\" href=\"https://dom.spec.whatwg.org/#text\" id=\"ref-for-text④\">Text</a></code> nodes <var>nodes</var>, and booleans <var>wordStartBounded</var> and <var>wordEndBounded</var>, follow these steps: \n    <div class=\"note\" role=\"note\">\n      Optionally, this will only return a match if the matched text begins and/or\n  ends on a <a data-link-type=\"dfn\" href=\"#word-boundary\" id=\"ref-for-word-boundary\">word boundary</a>. For example: \n     <div class=\"example\" id=\"example-27ab4025\">\n      <a class=\"self-link\" href=\"#example-27ab4025\"></a> The query string “range” will always match in “mountain range”, but \n      <ol>\n       <li data-md>\n        <p>When requiring a word boundary at the beginning, it will not match in “color orange”.</p>\n       <li data-md>\n        <p>When requiring a word boundary at the end, it will not match in “forest ranger”.</p>\n      </ol>\n     </div>\n     <p>See <a href=\"#word-boundaries\">§ 3.6.2 Word Boundaries</a> for details and more examples.</p>\n    </div>\n    <ol class=\"algorithm\">\n     <li data-md>\n      <p>Let <var>searchBuffer</var> be the <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#string-concatenate\" id=\"ref-for-string-concatenate\">concatenation</a> of the <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-cd-data\" id=\"ref-for-concept-cd-data①\">data</a> of each item in <var>nodes</var>.</p>\n      <p class=\"issue\" id=\"issue-96fe4755\"><a class=\"self-link\" href=\"#issue-96fe4755\"></a> <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-cd-data\" id=\"ref-for-concept-cd-data②\">data</a> is not\ncorrect here since that’s the text data as it exists in the DOM. This\nalgorithm means to run over the text as rendered (and then convert back\nto Ranges in the DOM). <a href=\"https://github.com/WICG/scroll-to-text-fragment/issues/98\">[Issue #WICG/scroll-to-text-fragment#98]</a></p>\n     <li data-md>\n      <p>Let <var>searchStart</var> be 0.</p>\n     <li data-md>\n      <p>If the first item in <var>nodes</var> is <var>searchRange</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start-node\" id=\"ref-for-concept-range-start-node⑨\">start node</a> then\nset <var>searchStart</var> to <var>searchRange</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start-offset\" id=\"ref-for-concept-range-start-offset⑦\">start offset</a>.</p>\n     <li data-md>\n      <p>Let <var>start</var> and <var>end</var> be <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-bp\" id=\"ref-for-concept-range-bp④\">boundary points</a>, initially null.</p>\n     <li data-md>\n      <p>Let <var>matchIndex</var> be null.</p>\n     <li data-md>\n      <p>While <var>matchIndex</var> is null</p>\n      <ol>\n       <li data-md>\n        <p>Set <var>matchIndex</var> to the index of the first instance of <var>queryString</var> in <var>searchBuffer</var>, starting at <var>searchStart</var>. The string search must be\nperformed using a base character comparison, or the <a href=\"http://www.unicode.org/reports/tr10/#Multi_Level_Comparison\">primary\nlevel</a>, as defined in <a data-link-type=\"biblio\" href=\"#biblio-uts10\" title=\"Unicode Collation Algorithm\">[UTS10]</a>.</p>\n        <div class=\"note\" role=\"note\"> Intuitively, this is a case-insensitive search also ignoring accents, umlauts,\n  and other marks. </div>\n       <li data-md>\n        <p>If <var>matchIndex</var> is null, return null.</p>\n       <li data-md>\n        <p>Let <var>endIx</var> be <var>matchIndex</var> + <var>queryString</var>’s <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#string-length\" id=\"ref-for-string-length\">length</a>.</p>\n        <div class=\"note\" role=\"note\"> <var>endIx</var> is the index of the last character in the match + 1. </div>\n       <li data-md>\n        <p>Set <var>start</var> to the <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-bp\" id=\"ref-for-concept-range-bp⑤\">boundary point</a> result of <a data-link-type=\"dfn\" href=\"#get-boundary-point-at-index\" id=\"ref-for-get-boundary-point-at-index\">get boundary point at\nindex</a> <var>matchIndex</var> run over <var>nodes</var> with <var>isEnd</var> false.</p>\n       <li data-md>\n        <p>Set <var>end</var> to the <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-bp\" id=\"ref-for-concept-range-bp⑥\">boundary point</a> result of <a data-link-type=\"dfn\" href=\"#get-boundary-point-at-index\" id=\"ref-for-get-boundary-point-at-index①\">get boundary point at\nindex</a> <var>endIx</var> run over <var>nodes</var> with <var>isEnd</var> true.</p>\n       <li data-md>\n        <p>If <var>wordStartBounded</var> is true and <var>matchIndex</var> <a data-link-type=\"dfn\" href=\"#is-at-a-word-boundary\" id=\"ref-for-is-at-a-word-boundary\">is\nnot at a word boundary</a> in <var>searchBuffer</var>, given the <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/dom.html#language\" id=\"ref-for-language\">language</a> from <var>start</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#boundary-point-node\" id=\"ref-for-boundary-point-node\">node</a> as the <var>locale</var>; or <var>wordEndBounded</var> is true and <var>matchIndex</var> + <var>queryString</var>’s <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#string-length\" id=\"ref-for-string-length①\">length</a> <a data-link-type=\"dfn\" href=\"#is-at-a-word-boundary\" id=\"ref-for-is-at-a-word-boundary①\">is not at a word boundary</a> in <var>searchBuffer</var>, given the <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/dom.html#language\" id=\"ref-for-language①\">language</a> from <var>end</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#boundary-point-node\" id=\"ref-for-boundary-point-node①\">node</a> as the <var>locale</var>:</p>\n        <ol>\n         <li data-md>\n          <p>Set <var>searchStart</var> to <var>matchIndex</var> + 1.</p>\n         <li data-md>\n          <p>Set <var>matchIndex</var> to null.</p>\n        </ol>\n      </ol>\n     <li data-md>\n      <p>Let <var>endInset</var> be 0.</p>\n     <li data-md>\n      <p>If the last item in <var>nodes</var> is <var>searchRange</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-end-node\" id=\"ref-for-concept-range-end-node②\">end node</a> then set <var>endInset</var> to (<var>searchRange</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-end-node\" id=\"ref-for-concept-range-end-node③\">end node</a>'s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-node-length\" id=\"ref-for-concept-node-length②\">length</a> − <var>searchRange</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-end-offset\" id=\"ref-for-concept-range-end-offset\">end offset</a>)</p>\n      <div class=\"note\" role=\"note\"> <var>endInset</var> is the offset from the last position in the last node in the\n  reverse direction. Alternatively, it is the length of the node that’s not\n  included in the range. </div>\n     <li data-md>\n      <p>If <var>matchIndex</var> + <var>queryString</var>’s <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#string-length\" id=\"ref-for-string-length②\">length</a> is greater than <var>searchBuffer</var>’s length − <var>endInset</var> return null.</p>\n      <div class=\"note\" role=\"note\"> If the match runs past the end of the search range, return null. </div>\n     <li data-md>\n      <p><a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#assert\" id=\"ref-for-assert⑦\">Assert</a>: <var>start</var> and <var>end</var> are non-null, valid <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-bp\" id=\"ref-for-concept-range-bp⑦\">boundary points</a> in <var>searchRange</var>.</p>\n     <li data-md>\n      <p>Return a <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range\" id=\"ref-for-concept-range③⓪\">range</a> with <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-start\" id=\"ref-for-concept-range-start①⑧\">start</a> <var>start</var> and <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-end\" id=\"ref-for-concept-range-end①⑤\">end</a> <var>end</var>.</p>\n    </ol>\n   </div>\n   <div class=\"algorithm\" data-algorithm=\"boundary point at index\">\n     To <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"get-boundary-point-at-index\">get boundary point at index</dfn>, given an integer <var>index</var>, <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#list\" id=\"ref-for-list①⓪\">list</a> of <code class=\"idl\"><a data-link-type=\"idl\" href=\"https://dom.spec.whatwg.org/#text\" id=\"ref-for-text⑤\">Text</a></code> nodes <var>nodes</var>, and a boolean <var>isEnd</var>, follow these steps: \n    <div class=\"note\" role=\"note\">\n     <p> This is a small helper routine used by the steps above to determine which\n    node a given index in the concatenated string belongs to. </p>\n     <p> <var>isEnd</var> is used to differentiate start and end indices. An end index points\n    to the \"one-past-last\" character of the matching string. If the match ends\n    at node boundary, we want the end offset to remain within that node, rather\n    than the start of the next node. </p>\n    </div>\n    <ol class=\"algorithm\">\n     <li data-md>\n      <p>Let <var>counted</var> be 0.</p>\n     <li data-md>\n      <p>For each <var>curNode</var> of <var>nodes</var>:</p>\n      <ol>\n       <li data-md>\n        <p>Let <var>nodeEnd</var> be <var>counted</var> + <var>curNode</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-node-length\" id=\"ref-for-concept-node-length③\">length</a>.</p>\n       <li data-md>\n        <p>If <var>isEnd</var> is true, add 1 to <var>nodeEnd</var>.</p>\n       <li data-md>\n        <p>If <var>nodeEnd</var> is greater than <var>index</var> then:</p>\n        <ol>\n         <li data-md>\n          <p>Return the <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-range-bp\" id=\"ref-for-concept-range-bp⑧\">boundary point</a> (<var>curNode</var>, <var>index</var> − <var>counted</var>).</p>\n        </ol>\n       <li data-md>\n        <p>Increment <var>counted</var> by <var>curNode</var>’s <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-node-length\" id=\"ref-for-concept-node-length④\">length</a>.</p>\n      </ol>\n     <li data-md>\n      <p>Return null.</p>\n    </ol>\n   </div>\n   <h4 class=\"heading settled\" data-level=\"3.6.2\" id=\"word-boundaries\"><span class=\"secno\">3.6.2. </span><span class=\"content\">Word Boundaries</span><a class=\"self-link\" href=\"#word-boundaries\"></a></h4>\n   <div class=\"note\" role=\"note\"> Limiting matching to word boundaries is one of the mitigations to limit\n  cross-origin information leakage. </div>\n   <div class=\"note\" role=\"note\"> See <a href=\"https://github.com/tc39/proposal-intl-segmenter\">Intl.Segmenter</a>, a\n  proposal to specify unicode segmentation, including word segmentation. Once\n  specified, this algorithm can be improved by making use of the Intl.Segmenter\n  API for word boundary matching. </div>\n   <p> A <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"word-boundary\">word boundary</dfn> is defined in <a data-link-type=\"biblio\" href=\"#biblio-uax29\" title=\"Unicode Text Segmentation\">[UAX29]</a> in <a href=\"https://www.unicode.org/reports/tr29/tr29-43.html#Word_Boundaries\">Unicode Text Segmentation § Word_Boundaries</a>. <a href=\"https://www.unicode.org/reports/tr29/tr29-43.html#Default_Word_Boundaries\">Unicode Text Segmentation § Default_Word_Boundaries</a> defines a\n  default set of what constitutes a word boundary, but as the specification\n  mentions, a more sophisticated algorithm should be used based on the locale. </p>\n   <p> Dictionary-based word bounding should take specific care in locales without a\n  word-separating character. E.g. In English, words are separated by the space\n  character (' '); however, in Japanese there is no character that separates one\n  word from the next. In such cases, and where the alphabet contains fewer\n  than 100 characters, the dictionary must not contain more than 20% of the\n  alphabet as valid, one-letter words. </p>\n   <p>A <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"locale\">locale</dfn> is a <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#string\" id=\"ref-for-string⑥\">string</a> containing a valid <a data-link-type=\"biblio\" href=\"#biblio-bcp47\" title=\"Tags for Identifying Languages\">[BCP47]</a> language tag, or the empty string. An empty string indicates that the primary\nlanguage is unknown.</p>\n   <p>A substring is <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"word-bounded\">word bounded</dfn> in a <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#string\" id=\"ref-for-string⑦\">string</a> <var>text</var>,\ngiven <a data-link-type=\"dfn\" href=\"#locale\" id=\"ref-for-locale\">locales</a> <var>startLocale</var> and <var>endLocale</var>, if both the position of its\nfirst character <a data-link-type=\"dfn\" href=\"#is-at-a-word-boundary\" id=\"ref-for-is-at-a-word-boundary②\">is at a word boundary</a> given <var>startLocale</var>, and the position\nafter its last character <a data-link-type=\"dfn\" href=\"#is-at-a-word-boundary\" id=\"ref-for-is-at-a-word-boundary③\">is at a word boundary</a> given <var>endLocale</var>.</p>\n   <p>A number <var>position</var> <dfn class=\"dfn-paneled\" data-dfn-type=\"dfn\" data-noexport id=\"is-at-a-word-boundary\">is at a word boundary</dfn> in a <a data-link-type=\"dfn\" href=\"https://infra.spec.whatwg.org/#string\" id=\"ref-for-string⑧\">string</a> <var>text</var>, given a <a data-link-type=\"dfn\" href=\"#locale\" id=\"ref-for-locale①\">locale</a> <var>locale</var>, if, using <var>locale</var>, either a <a data-link-type=\"dfn\" href=\"#word-boundary\" id=\"ref-for-word-boundary①\">word\nboundary</a> immediately precedes the <var>position</var>th code unit, or <var>text</var>’s length\nis more than 0 and <var>position</var> equals either 0 or <var>text</var>’s length.</p>\n   <div class=\"note\" role=\"note\">\n     Intuitively, a substring is <a data-link-type=\"dfn\" href=\"#word-bounded\" id=\"ref-for-word-bounded\">word bounded</a> if it neither begins nor ends in\n  the middle of a word. \n    <p>In languages with a word separator (e.g. \" \" space) this is (mostly)\n  straightforward; though there are details covered by the above technical\n  reports such as new lines, hyphenations, quotes, etc.</p>\n    <p>Some languages do not have such a separator (notably,\n  Chinese/Japanese/Korean). Languages such as these requires dictionaries to\n  determine what a valid word in the given locale is.</p>\n   </div>\n   <div class=\"example\" id=\"example-0a0acb46\">\n    <a class=\"self-link\" href=\"#example-0a0acb46\"></a> \n    <p> Text fragments are restricted such that match terms, when combined with\n    their adjacent context terms, are word bounded. For example, in an\n    exact search like <code>prefix,start,suffix</code>, <code>\"prefix+start+suffix\"</code> will match only if the entire result is word bounded. However, in a\n    range search like <code>prefix,start,end,suffix</code>, a match is\n    found only if both <code>\"prefix+start\"</code> and <code>\"end+suffix\"</code> are\n    word bounded. </p>\n    <p> The goal is that a third-party must already know the full tokens they are\n    matching against. A range match like <code>start,end</code> must be\n    word bounded on the inside of the two terms; otherwise a third party could\n    use this repeatedly to try and reveal a token (e.g. on a page with <code>\"Balance: 123,456 $\"</code>, a third-party could set <code>prefix=\"Balance: \", end=\"$\"</code> and vary <code>start</code> to try and guess the numeric token one digit at a time). </p>\n    <p> For more details, refer to the <a href=\"https://docs.google.com/document/d/1YHcl1-vE_ZnZ0kL2almeikAj2gkwCq8_5xwIae7PVik/edit#heading=h.78iny7nejmx2\">Security Review Doc</a> </p>\n   </div>\n   <div class=\"example\" id=\"example-1b2a6f00\"><a class=\"self-link\" href=\"#example-1b2a6f00\"></a> The substring \"mountain range\" is word bounded within the string \"An impressive\n  mountain range\" but not within \"An impressive mountain ranger\". </div>\n   <div class=\"example\" id=\"example-c7882c95\"><a class=\"self-link\" href=\"#example-c7882c95\"></a> In the Japanese string \"<span lang=\"ja\">ウィキペディアへようこそ</span>\" (Welcome to Wikipedia),\n  \"<span lang=\"ja\">ようこそ</span>\" (Welcome) is considered word-bounded but \"<span lang=\"ja\">ようこ</span>\" is not. </div>\n   <h3 class=\"heading settled\" data-level=\"3.7\" id=\"indicating-the-text-match\"><span class=\"secno\">3.7. </span><span class=\"content\">Indicating The Text Match</span><a class=\"self-link\" href=\"#indicating-the-text-match\"></a></h3>\n   <p>The UA may choose to scroll the text fragment into view as part of the <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#try-to-scroll-to-the-fragment\" id=\"ref-for-try-to-scroll-to-the-fragment①\">try to scroll to the fragment</a> steps or by some other mechanism;\nhowever, it is not required to scroll the match into view.</p>\n   <p>The UA should visually indicate the matched text in some way such that the user\nis made aware of the text match, such as with a high-contrast highlight.</p>\n   <p>The UA should provide to the user some method of dismissing the match, such\nthat the matched text no longer appears visually indicated.</p>\n   <p>The exact appearance and mechanics of the indication are left as UA-defined.\nHowever, the UA must not use any methods observable by author script, such as\nthe Document’s <a href=\"https://w3c.github.io/selection-api/#dfn-selection\"> selection</a>, to indicate the text match. Doing so could allow attack vectors\nfor content exfiltration.</p>\n   <p>The UA must not visually indicate any provided context terms.</p>\n   <p>Since the indicator is not part of the document’s content, UAs should consider\nways to differentiate it from the page’s content as perceived by the user.</p>\n   <div class=\"example\" id=\"example-30d9320e\"><a class=\"self-link\" href=\"#example-30d9320e\"></a> The UA could provide an in-product help prompt the first few times the\n  indicator appears to help train the user that it comes from the linking page\n  and is provided by the UA. </div>\n   <h4 class=\"heading settled\" data-level=\"3.7.1\" id=\"urls-in-ua-features\"><span class=\"secno\">3.7.1. </span><span class=\"content\">URLs in UA features</span><a class=\"self-link\" href=\"#urls-in-ua-features\"></a></h4>\n   <p>UAs provide a number of consumers for a document’s URL (outside of programmatic\nAPIs like <code>window.location</code>). Examples include a location bar\nindicating the URL of the currently visible document, or the URL used when a\nuser requests to create a bookmark for the current page.</p>\n   <p>To avoid user confusion, UAs should be consistent in whether such URLs include\nthe <a data-link-type=\"dfn\" href=\"#fragment-directive\" id=\"ref-for-fragment-directive⑧\">fragment directive</a>. This section provides a default set of\nrecommendations for how UAs can handle these cases.</p>\n   <div class=\"note\" role=\"note\">\n    <p> We provide these as a baseline for consistent behavior; however, as these\n  features don’t affect cross-UA interoperability, they are not strict\n  conformance requirements. </p>\n    <p> Exact behavior is left up to the implementing UA which can have differing\n  constraints or reasons for modifying the behavior. e.g. UAs can allow users\n  to configure defaults or expose UI options so users can choose whether they\n  prefer to include fragment directives in these URLs. </p>\n    <p>It’s also useful to allow UAs to experiment with providing a better\n  experience. E.g. perhaps the UA’s displayed URL can elide the text fragment if\n  the user scrolls it out of view?</p>\n    <p></p>\n   </div>\n   <p>The general principle is that a URL should include the <a data-link-type=\"dfn\" href=\"#fragment-directive\" id=\"ref-for-fragment-directive⑨\">fragment directive</a> only while the visual indicator is visible (i.e. not dismissed). If the user\ndismisses the indicator, the URL should reflect that by also removing the the <a data-link-type=\"dfn\" href=\"#fragment-directive\" id=\"ref-for-fragment-directive①⓪\">fragment directive</a>.</p>\n   <p>If the URL includes a text fragment but a match wasn’t found in the current\npage, the UA may choose to omit it from the exposed URL.</p>\n   <div class=\"note\" role=\"note\">\n    <p> A text fragment that isn’t found on the page can be useful information to\n  surface to a user to indicate that the page has changed since the link\n  was created. </p>\n    <p> However, it’s unlikely to be useful to the user in a bookmark. </p>\n   </div>\n   <p>A few common examples are provided below.</p>\n   <div class=\"note\" role=\"note\"> We use \"text fragment\" and \"fragment directive\" interchangeably here as text\n  fragments are assumed to be the only kind of directive. If additional\n  directives are added in the future, the UX in these cases will have to be\n  re-evaluated separately for new directive types. </div>\n   <h5 class=\"heading settled\" data-level=\"3.7.1.1\" id=\"urls-in-location-bar\"><span class=\"secno\">3.7.1.1. </span><span class=\"content\">Location Bar</span><a class=\"self-link\" href=\"#urls-in-location-bar\"></a></h5>\n   <p>The location bar’s URL should include a text fragment while it is visually\nindicated. The <a data-link-type=\"dfn\" href=\"#fragment-directive\" id=\"ref-for-fragment-directive①①\">fragment directive</a> should be stripped from the location bar\nURL when the user dismisses the indication.</p>\n   <p>It is recommended that the text fragment be displayed in the location bar’s URL\neven if a match wasn’t located in the document.</p>\n   <h5 class=\"heading settled\" data-level=\"3.7.1.2\" id=\"urls-in-bookmarks\"><span class=\"secno\">3.7.1.2. </span><span class=\"content\">Bookmarks</span><a class=\"self-link\" href=\"#urls-in-bookmarks\"></a></h5>\n   <p>Many UAs provide a \"bookmark\" feature allowing users to store a convenient link\nto the current page in the UA’s interface.</p>\n   <p>A newly created bookmark should, by default, include the <a data-link-type=\"dfn\" href=\"#fragment-directive\" id=\"ref-for-fragment-directive①②\">fragment directive</a> in the URL if, and only if, a match was found and the visual indicator hasn’t\nbeen dismissed.</p>\n   <p>Navigating to a URL from a bookmark should process a <a data-link-type=\"dfn\" href=\"#fragment-directive\" id=\"ref-for-fragment-directive①③\">fragment directive</a> as\nif it were navigated to in a typical navigation.</p>\n   <h5 class=\"heading settled\" data-level=\"3.7.1.3\" id=\"urls-in-sharing\"><span class=\"secno\">3.7.1.3. </span><span class=\"content\">Sharing</span><a class=\"self-link\" href=\"#urls-in-sharing\"></a></h5>\n   <p>Some UAs provide a method for users to share the current page with others,\ntypically by providing the URL to another app or messaging service.</p>\n   <p>When providing a URL in these situations, it should include the <a data-link-type=\"dfn\" href=\"#fragment-directive\" id=\"ref-for-fragment-directive①④\">fragment\ndirective</a> if, and only if, a match was found and the visual indicator hasn’t\nbeen dismissed.</p>\n   <h3 class=\"heading settled\" data-level=\"3.8\" id=\"document-policy-integration\"><span class=\"secno\">3.8. </span><span class=\"content\">Document Policy Integration</span><a class=\"self-link\" href=\"#document-policy-integration\"></a></h3>\n   <p>This specification defines a <a href=\"https://wicg.github.io/document-policy#configuration-point\">configuration point</a> in <a data-link-type=\"biblio\" href=\"#biblio-document-policy\" title=\"Document Policy\">Document Policy</a> with name \"force-load-at-top\". Its <a href=\"https://wicg.github.io/document-policy#configuration-point-type\">type</a> is <code>boolean</code> with <a href=\"https://wicg.github.io/document-policy#configuration-point-default-value\">default value</a> <code>false</code>.</p>\n   <div class=\"note\" role=\"note\"> When enabled, this policy disables all automatic scroll-on-load features:\n  text-fragments, element fragments, history scroll restoration. </div>\n   <div class=\"example\" id=\"example-a128f34b\">\n    <a class=\"self-link\" href=\"#example-a128f34b\"></a> Suppose the user navigates to <code>https://example.com#:~:text=foo</code>. The\n  example.com server response includes the header: \n<pre>Document-Policy: force-load-at-top\n</pre>\n    <p>When the page loads, the element containing \"foo\" will be marked as the\n  indicated part and set as the document’s target element. However, \"foo\"\n  will not be scrolled into view.</p>\n   </div>\n   <p>Fragment-based scroll blocking from this policy is specified in an amendment to the <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#scroll-to-the-fragment-identifier\" id=\"ref-for-scroll-to-the-fragment-identifier④\">scroll to the fragment</a> algorithm in the <a href=\"#navigating-to-text-fragment\">§ 3.6 Navigating to a Text Fragment</a> section of this document.</p>\n   <p>History scroll restoration is blocked by amending the <a data-link-type=\"dfn\" href=\"https://html.spec.whatwg.org/multipage/browsing-the-web.html#restore-persisted-state\" id=\"ref-for-restore-persisted-state①\">restore\npersisted state</a> steps by inserting a new step after 2:</p>\n   <ol start=\"3\">\n    <li data-md>\n     <p><a href=\"https://wicg.github.io/document-policy#algo-get-policy-value\">Get\nthe document policy value</a> of the \"force-load-at-top\" feature for the <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-document\" id=\"ref-for-concept-document①⓪\">Document</a>. If\nthe result is true, then the user agent should not restore the scroll\nposition for the <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-document\" id=\"ref-for-concept-document①①\">Document</a> or any of its scrollable regions.</p>\n   </ol>\n   <h3 class=\"heading settled\" data-level=\"3.9\" id=\"feature-detectability\"><span class=\"secno\">3.9. </span><span class=\"content\">Feature Detectability</span><a class=\"self-link\" href=\"#feature-detectability\"></a></h3>\n   <p>For feature detectability, we propose adding a new FragmentDirective interface\nthat is exposed via <code>document.fragmentDirective</code> if the UA supports\nthe feature.</p>\n<pre class=\"idl highlight def\">[<a class=\"idl-code\" data-link-type=\"extended-attribute\" href=\"https://webidl.spec.whatwg.org/#Exposed\" id=\"ref-for-Exposed\"><c- g>Exposed</c-></a>=<c- n>Window</c->]\n<c- b>interface</c-> <dfn class=\"dfn-paneled idl-code\" data-dfn-type=\"interface\" data-export id=\"fragmentdirective\"><code><c- g>FragmentDirective</c-></code></dfn> {\n};\n</pre>\n   <p>We amend the <code class=\"idl\"><a data-link-type=\"idl\" href=\"https://dom.spec.whatwg.org/#document\" id=\"ref-for-document\">Document</a></code> interface to include a <code>fragmentDirective</code> property:</p>\n<pre class=\"idl highlight def\"><c- b>partial</c-> <c- b>interface</c-> <a class=\"idl-code\" data-link-type=\"interface\" href=\"https://dom.spec.whatwg.org/#document\" id=\"ref-for-document①\"><c- g>Document</c-></a> {\n    [<a class=\"idl-code\" data-link-type=\"extended-attribute\" href=\"https://webidl.spec.whatwg.org/#SameObject\" id=\"ref-for-SameObject\"><c- g>SameObject</c-></a>] <c- b>readonly</c-> <c- b>attribute</c-> <a data-link-type=\"idl-name\" href=\"#fragmentdirective\" id=\"ref-for-fragmentdirective\"><c- n>FragmentDirective</c-></a> <dfn class=\"idl-code\" data-dfn-for=\"Document\" data-dfn-type=\"attribute\" data-export data-readonly data-type=\"FragmentDirective\" id=\"dom-document-fragmentdirective\"><code><c- g>fragmentDirective</c-></code><a class=\"self-link\" href=\"#dom-document-fragmentdirective\"></a></dfn>;\n};\n</pre>\n   <p>This object may be used to expose additional information about the text\nfragment or other fragment directives in the future.</p>\n   <h2 class=\"heading settled\" data-level=\"4\" id=\"generating-text-fragment-directives\"><span class=\"secno\">4. </span><span class=\"content\">Generating Text Fragment Directives</span><a class=\"self-link\" href=\"#generating-text-fragment-directives\"></a></h2>\n   <div class=\"note\" role=\"note\"> This section is non-normative. </div>\n   <p>This section contains recommendations for UAs automatically generating URLs\nwith a <a data-link-type=\"dfn\" href=\"#text-directive\" id=\"ref-for-text-directive①④\">text directive</a>. These recommendations aren’t normative but\nare provided to ensure generated URLs result in maximally stable and usable\nURLs.</p>\n   <h3 class=\"heading settled\" data-level=\"4.1\" id=\"prefer-exact-matching-to-range-based\"><span class=\"secno\">4.1. </span><span class=\"content\">Prefer Exact Matching To Range-based</span><a class=\"self-link\" href=\"#prefer-exact-matching-to-range-based\"></a></h3>\n   <p>The match text can be provided either as an exact string \"text=foo%20bar%20baz\"\nor as a range \"text=foo,bar\".</p>\n   <p>Prefer to specify the entire string where practical. This ensures that if the\ndestination page is removed or changed, the intended destination can still be\nderived from the URL itself.</p>\n   <div class=\"example\" id=\"example-53e82e58\">\n    <a class=\"self-link\" href=\"#example-53e82e58\"></a> Suppose we wish to craft a URL to\n  https://en.wikipedia.org/wiki/History_of_computing quoting the sentence: \n<pre>The first recorded idea of using digital electronics for computing was the\n1931 paper \"The Use of Thyratrons for High Speed Automatic Counting of\nPhysical Phenomena\" by C. E. Wynn-Williams.\n</pre>\n    <p>We could create a range-based match like so:</p>\n    <p><a href=\"https://en.wikipedia.org/wiki/History_of_computing#:~:text=The%20first%20recorded,Williams\"> https://en.wikipedia.org/wiki/History_of_computing#:~:text=The%20first%20recorded,Williams</a></p>\n    <p>Or we could encode the entire sentence using an exact match term:</p>\n    <p><a href=\"https://en.wikipedia.org/wiki/History_of_computing#:~:text=The%20first%20recorded%20idea%20of%20using%20digital%20electronics%20for%20computing%20was%20the%201931%20paper%20%22The%20Use%20of%20Thyratrons%20for%20High%20Speed%20Automatic%20Counting%20of%20Physical%20Phenomena%22%20by%20C.%20E.%20Wynn-Williams\"> https://en.wikipedia.org/wiki/History_of_computing#:~:text=The%20first%20recorded%20idea%20of%20using%20digital%20electronics%20for%20computing%20was%20the%201931%20paper%20%22The%20Use%20of%20Thyratrons%20for%20High%20Speed%20Automatic%20Counting%20of%20Physical%20Phenomena%22%20by%20C.%20E.%20Wynn-Williams</a></p>\n    <p>The range-based match is less stable, meaning that if the page is changed to\n  include another instance of \"The first recorded\" somewhere earlier in the\n  page, the link will now target an unintended text snippet.</p>\n    <p>The range-based match is also less useful semantically. If the page is\n  changed to remove the sentence, the user won’t know what the intended\n  target was. In the exact match case, the user can read, or the UA can\n  surface, the text that was being searched for but not found.</p>\n   </div>\n   <p>Range-based matches can be helpful when the quoted text is excessively long\nand encoding the entire string would produce an unwieldy URL.</p>\n   <p>Text snippets shorter than 300 characters are encouraged to be encoded using an\nexact match. Above this limit, the UA can encode the string as a range-based\nmatch.</p>\n   <div class=\"note\" role=\"note\"> TODO:  Can we determine the above limit in some less arbitrary way? </div>\n   <h3 class=\"heading settled\" data-level=\"4.2\" id=\"use-context-only-when-necessary\"><span class=\"secno\">4.2. </span><span class=\"content\">Use Context Only When Necessary</span><a class=\"self-link\" href=\"#use-context-only-when-necessary\"></a></h3>\n   <p>Context terms allow the <a data-link-type=\"dfn\" href=\"#text-directive\" id=\"ref-for-text-directive①⑤\">text directive</a> to disambiguate text\nsnippets on a page. However, their use can make the URL more brittle in some\ncases. Often, the desired string will start or end at an element boundary. The\ncontext will therefore exist in an adjacent element. Changes to the page\nstructure could invalidate the <a data-link-type=\"dfn\" href=\"#text-directive\" id=\"ref-for-text-directive①⑥\">text directive</a> since the context and\nmatch text will no longer appear to be adjacent.</p>\n   <div class=\"example\" id=\"example-7a86f6f5\">\n    <a class=\"self-link\" href=\"#example-7a86f6f5\"></a> Suppose we wish to craft a URL for the following text: \n<pre>&lt;div class=\"section\">HEADER&lt;/div>\n&lt;div class=\"content\">Text to quote&lt;/div>\n</pre>\n    <p>We could craft the <a data-link-type=\"dfn\" href=\"#text-directive\" id=\"ref-for-text-directive①⑦\">text directive</a> as follows:</p>\n<pre>text=HEADER-,Text%20to%20quote\n</pre>\n    <p>However, suppose the page changes to add a \"[edit]\" link beside all section\n  headers. This would now break the URL.</p>\n   </div>\n   <p>Where a text snippet is long enough and unique, a UAs are encouraged to avoid\nadding superfluous context terms.</p>\n   <p>Use context only if one of the following is true:</p>\n   <ul>\n    <li>The UA determines the quoted text is ambiguous\n    <li>The quoted text contains 3 or fewer words\n   </ul>\n   <div class=\"note\" role=\"note\"> TODO: Determine the numeric limit above in less arbitrary way. </div>\n   <h3 class=\"heading settled\" data-level=\"4.3\" id=\"determine-if-fragment-id-is-needed\"><span class=\"secno\">4.3. </span><span class=\"content\">Determine If Fragment Id Is Needed</span><a class=\"self-link\" href=\"#determine-if-fragment-id-is-needed\"></a></h3>\n   <p>When the UA navigates to a URL containing a <a data-link-type=\"dfn\" href=\"#text-directive\" id=\"ref-for-text-directive①⑧\">text directive</a>, it will\nfallback to scrolling into view a regular element-id based fragment if it\nexists and the text fragment isn’t found.</p>\n   <p>This can be useful to provide a fallback, in case the text in the document\nchanges, invalidating the <a data-link-type=\"dfn\" href=\"#text-directive\" id=\"ref-for-text-directive①⑨\">text directive</a>.</p>\n   <div class=\"example\" id=\"example-5990805b\">\n    <a class=\"self-link\" href=\"#example-5990805b\"></a> Suppose we wish to craft a URL to\n  https://en.wikipedia.org/wiki/History_of_computing quoting the sentence: \n<pre>The earliest known tool for use in computation is the Sumerian abacus\n</pre>\n    <p>By specifying the section that the text appears in, we ensure that, if the\n  text is changed or removed, the user will still be pointed to the relevant\n  section:</p>\n    <p><a href=\"https://en.wikipedia.org/wiki/History_of_computing#Early_computation:~:text=The%20earliest%20known%20tool%20for%20use%20in%20computation%20is%20the%20Sumerian%20abacus\"> https://en.wikipedia.org/wiki/History_of_computing#Early_computation:~:text=The%20earliest%20known%20tool%20for%20use%20in%20computation%20is%20the%20Sumerian%20abacus</a></p>\n   </div>\n   <p>However, UAs should take care that the fallback element-id fragment is the\ncorrect one:</p>\n   <div class=\"example\" id=\"example-3c4e565c\">\n    <a class=\"self-link\" href=\"#example-3c4e565c\"></a> Suppose the user navigates to\n  https://en.wikipedia.org/wiki/History_of_computing#Early_computation. They\n  now scroll down to the Symbolic Computations section. There, they select a\n  text snippet and choose to create a URL to it: \n<pre>By the late 1960s, computer systems could perform symbolic algebraic\nmanipulations\n</pre>\n    <p>Even though the current URL of the page is:\n  https://en.wikipedia.org/wiki/History_of_computing#Early_computation, using\n  #Early_computation as a fallback is inappropriate. If the above sentence is\n  changed or removed, the page will load in the #Early_computation section\n  which could be quite confusing to the user.</p>\n    <p>If the UA cannot reliably determine an appropriate fragment to fallback to,\n  it should remove the fragment id from the URL:</p>\n    <p><a href=\"https://en.wikipedia.org/wiki/History_of_computing#:~:text=By%20the%20late%201960s,%20computer%20systems%20could%20perform%20symbolic%20algebraic%20manipulations\"> https://en.wikipedia.org/wiki/History_of_computing#:~:text=By%20the%20late%201960s,%20computer%20systems%20could%20perform%20symbolic%20algebraic%20manipulations</a></p>\n   </div>\n  </main>\n  <div data-fill-with=\"conformance\">\n   <h2 class=\"no-ref no-num heading settled\" id=\"w3c-conformance\"><span class=\"content\">Conformance</span><a class=\"self-link\" href=\"#w3c-conformance\"></a></h2>\n   <h3 class=\"no-ref no-num heading settled\" id=\"w3c-conventions\"><span class=\"content\">Document conventions</span><a class=\"self-link\" href=\"#w3c-conventions\"></a></h3>\n   <p>Conformance requirements are expressed\n    with a combination of descriptive assertions\n    and RFC 2119 terminology.\n    The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL”\n    in the normative parts of this document\n    are to be interpreted as described in RFC 2119.\n    However, for readability,\n    these words do not appear in all uppercase letters in this specification. </p>\n   <p>All of the text of this specification is normative\n    except sections explicitly marked as non-normative, examples, and notes. <a data-link-type=\"biblio\" href=\"#biblio-rfc2119\" title=\"Key words for use in RFCs to Indicate Requirement Levels\">[RFC2119]</a> </p>\n   <p>Examples in this specification are introduced with the words “for example”\n    or are set apart from the normative text\n    with <code>class=\"example\"</code>,\n    like this: </p>\n   <div class=\"example\" id=\"w3c-example\">\n    <a class=\"self-link\" href=\"#w3c-example\"></a> \n    <p>This is an example of an informative example. </p>\n   </div>\n   <p>Informative notes begin with the word “Note”\n    and are set apart from the normative text\n    with <code>class=\"note\"</code>,\n    like this: </p>\n   <p class=\"note\" role=\"note\">Note, this is an informative note.</p>\n   <details class=\"wpt-tests-block\" dir=\"ltr\" lang=\"en\" open>\n    <summary>Tests</summary>\n    <p>Tests relating to the content of this specification\n                     may be documented in “Tests” blocks like this one.\n                     Any such block is non-normative.</p>\n    <ul class=\"wpt-tests-list\"></ul>\n    <hr>\n   </details>\n  </div>\n<script src=\"https://www.w3.org/scripts/TR/2021/fixup.js\"></script>\n  <h2 class=\"no-num no-ref heading settled\" id=\"index\"><span class=\"content\">Index</span><a class=\"self-link\" href=\"#index\"></a></h2>\n  <h3 class=\"no-num no-ref heading settled\" id=\"index-defined-here\"><span class=\"content\">Terms defined by this specification</span><a class=\"self-link\" href=\"#index-defined-here\"></a></h3>\n  <ul class=\"index\">\n   <li><a href=\"#characterstring\">CharacterString</a><span>, in § 3.3.3</span>\n   <li><a href=\"#check-if-a-text-directive-can-be-scrolled\">check if a text directive can be scrolled</a><span>, in § 3.5.4</span>\n   <li><a href=\"#directives\">directives</a><span>, in § 3.3</span>\n   <li>\n    directive state\n    <ul>\n     <li><a href=\"#directive-state\">definition of</a><span>, in § 3.3.1</span>\n     <li><a href=\"#she-directive-state\">dfn for she</a><span>, in § 3.3.1</span>\n    </ul>\n   <li><a href=\"#text-directive-end\">end</a><span>, in § 3.4</span>\n   <li><a href=\"#explicitchar\">ExplicitChar</a><span>, in § 3.3.3</span>\n   <li><a href=\"#find-a-range-from-a-node-list\">find a range from a node list</a><span>, in § 3.6.1</span>\n   <li><a href=\"#find-a-range-from-a-text-directive\">find a range from a text directive</a><span>, in § 3.6.1</span>\n   <li><a href=\"#find-a-string-in-range\">find a string in range</a><span>, in § 3.6.1</span>\n   <li><a href=\"#first-common-ancestor\">first common ancestor</a><span>, in § 3.6</span>\n   <li><a href=\"#fragment-directive\">fragment directive</a><span>, in § 3.3</span>\n   <li>\n    FragmentDirective\n    <ul>\n     <li><a href=\"#fragmentdirective\">(interface)</a><span>, in § 3.9</span>\n     <li><a href=\"#fragmentdirectiveproduction\">definition of</a><span>, in § 3.3.3</span>\n    </ul>\n   <li><a href=\"#dom-document-fragmentdirective\">fragmentDirective</a><span>, in § 3.9</span>\n   <li><a href=\"#fragment-directive-delimiter\">fragment directive delimiter</a><span>, in § 3.3</span>\n   <li><a href=\"#get-boundary-point-at-index\">get boundary point at index</a><span>, in § 3.6.1</span>\n   <li><a href=\"#has-block-level-display\">has block-level display</a><span>, in § 3.6.1</span>\n   <li><a href=\"#invoke-text-directives\">invoke text directives</a><span>, in § 3.6.1</span>\n   <li><a href=\"#is-at-a-word-boundary\">is at a word boundary</a><span>, in § 3.6.2</span>\n   <li><a href=\"#locale\">locale</a><span>, in § 3.6.2</span>\n   <li><a href=\"#nearest-block-ancestor\">nearest block ancestor</a><span>, in § 3.6.1</span>\n   <li><a href=\"#next-non-whitespace-position\">next non-whitespace position</a><span>, in § 3.6.1</span>\n   <li><a href=\"#non-searchable-subtree\">non-searchable subtree</a><span>, in § 3.6.1</span>\n   <li><a href=\"#parse-a-text-directive\">parse a text directive</a><span>, in § 3.4</span>\n   <li><a href=\"#parse-the-fragment-directive\">parse the fragment directive</a><span>, in § 3.4</span>\n   <li><a href=\"#document-pending-text-directives\">pending text directives</a><span>, in § 3.3.2</span>\n   <li><a href=\"#percent-decode-a-text-directive-term\">percent-decode a text directive term</a><span>, in § 3.4</span>\n   <li><a href=\"#percentencodedbyte\">PercentEncodedByte</a><span>, in § 3.3.3</span>\n   <li><a href=\"#text-directive-prefix\">prefix</a><span>, in § 3.4</span>\n   <li><a href=\"#remove-the-fragment-directive\">remove the fragment directive</a><span>, in § 3.3.1</span>\n   <li><a href=\"#search-invisible\">search invisible</a><span>, in § 3.6.1</span>\n   <li><a href=\"#shadow-including-parent\">shadow-including parent</a><span>, in § 3.6</span>\n   <li><a href=\"#text-directive-start\">start</a><span>, in § 3.4</span>\n   <li><a href=\"#text-directive-suffix\">suffix</a><span>, in § 3.4</span>\n   <li><a href=\"#text-directive\">text directive</a><span>, in § 3.4</span>\n   <li><a href=\"#textdirective\">TextDirective</a><span>, in § 3.3.3</span>\n   <li><a href=\"#text-directive-allowing-mime-type\">text directive allowing MIME type</a><span>, in § 3.5.4</span>\n   <li><a href=\"#textdirectiveexplicitchar\">TextDirectiveExplicitChar</a><span>, in § 3.3.3</span>\n   <li><a href=\"#textdirectiveparameters\">TextDirectiveParameters</a><span>, in § 3.3.3</span>\n   <li><a href=\"#textdirectiveprefix\">TextDirectivePrefix</a><span>, in § 3.3.3</span>\n   <li><a href=\"#textdirectivestring\">TextDirectiveString</a><span>, in § 3.3.3</span>\n   <li><a href=\"#textdirectivesuffix\">TextDirectiveSuffix</a><span>, in § 3.3.3</span>\n   <li>\n    text directive user activation\n    <ul>\n     <li><a href=\"#document-text-directive-user-activation\">dfn for document</a><span>, in § 3.5.4</span>\n     <li><a href=\"#request-text-directive-user-activation\">dfn for request</a><span>, in § 3.5.4</span>\n    </ul>\n   <li><a href=\"#unknowndirective\">UnknownDirective</a><span>, in § 3.3.3</span>\n   <li><a href=\"#navigation-params-user-involvement\">user involvement</a><span>, in § 3.5.4</span>\n   <li><a href=\"#validtextdirective\">ValidTextDirective</a><span>, in § 3.3.3</span>\n   <li><a href=\"#directive-state-value\">value</a><span>, in § 3.3.1</span>\n   <li><a href=\"#visible-text-node\">visible text node</a><span>, in § 3.6.1</span>\n   <li><a href=\"#word-boundary\">word boundary</a><span>, in § 3.6.2</span>\n   <li><a href=\"#word-bounded\">word bounded</a><span>, in § 3.6.2</span>\n  </ul>\n  <h3 class=\"no-num no-ref heading settled\" id=\"index-defined-elsewhere\"><span class=\"content\">Terms defined by reference</span><a class=\"self-link\" href=\"#index-defined-elsewhere\"></a></h3>\n  <ul class=\"index\">\n   <li>\n    <a data-link-type=\"biblio\">[CSS-CASCADE-5]</a> defines the following terms:\n    <ul>\n     <li><span class=\"dfn-paneled\" id=\"9cd25054\">computed value</span>\n    </ul>\n   <li>\n    <a data-link-type=\"biblio\">[CSS-DISPLAY-3]</a> defines the following terms:\n    <ul>\n     <li><span class=\"dfn-paneled\" id=\"66498315\">flex</span>\n     <li><span class=\"dfn-paneled\" id=\"a555386f\">grid</span>\n    </ul>\n   <li>\n    <a data-link-type=\"biblio\">[CSS-DISPLAY-4]</a> defines the following terms:\n    <ul>\n     <li><span class=\"dfn-paneled\" id=\"bb886fc6\">block</span>\n     <li><span class=\"dfn-paneled\" id=\"e7f0dd6c\">display</span>\n     <li><span class=\"dfn-paneled\" id=\"607244fc\">flow-root</span>\n     <li><span class=\"dfn-paneled\" id=\"96626f55\">list-item</span>\n     <li><span class=\"dfn-paneled\" id=\"55e8f5de\">none</span>\n     <li><span class=\"dfn-paneled\" id=\"abb2bed7\">table</span>\n     <li><span class=\"dfn-paneled\" id=\"12f8fb07\">visibility</span>\n     <li><span class=\"dfn-paneled\" id=\"6420cb11\">visible</span>\n    </ul>\n   <li>\n    <a data-link-type=\"biblio\">[CSSOM-VIEW-1]</a> defines the following terms:\n    <ul>\n     <li><span class=\"dfn-paneled\" id=\"2cbb079e\">scroll a target into view</span>\n    </ul>\n   <li>\n    <a data-link-type=\"biblio\">[DOM]</a> defines the following terms:\n    <ul>\n     <li><span class=\"dfn-paneled\" id=\"85394472\">Document</span>\n     <li><span class=\"dfn-paneled\" id=\"597088f0\">Text</span>\n     <li><span class=\"dfn-paneled\" id=\"4fef809c\">after</span>\n     <li><span class=\"dfn-paneled\" id=\"8a3e6de2\">boundary point</span>\n     <li><span class=\"dfn-paneled\" id=\"8aac8409\">collapsed</span>\n     <li><span class=\"dfn-paneled\" id=\"3f23ec71\">content type</span>\n     <li><span class=\"dfn-paneled\" id=\"212ee1f7\">data</span>\n     <li><span class=\"dfn-paneled\" id=\"cefd9ec1\">doctype</span>\n     <li><span class=\"dfn-paneled\" id=\"a973e0fe\">document</span>\n     <li><span class=\"dfn-paneled\" id=\"2f0ba72c\">document element</span>\n     <li><span class=\"dfn-paneled\" id=\"27d9b7ea\">element</span>\n     <li><span class=\"dfn-paneled\" id=\"5bbf7dec\">end</span>\n     <li><span class=\"dfn-paneled\" id=\"3edd98b4\">end node</span>\n     <li><span class=\"dfn-paneled\" id=\"203b148b\">end offset</span>\n     <li><span class=\"dfn-paneled\" id=\"6fba6744\">following</span>\n     <li><span class=\"dfn-paneled\" id=\"5d233601\">host</span>\n     <li><span class=\"dfn-paneled\" id=\"5e8d5f81\">length</span>\n     <li><span class=\"dfn-paneled\" id=\"d462b34f\">node</span>\n     <li><span class=\"dfn-paneled\" id=\"5216e1a0\">node document</span>\n     <li><span class=\"dfn-paneled\" id=\"c62cd7cf\">origin</span>\n     <li><span class=\"dfn-paneled\" id=\"d729a9ff\">parent</span>\n     <li><span class=\"dfn-paneled\" id=\"5afeceea\">parent element</span>\n     <li><span class=\"dfn-paneled\" id=\"8044ee41\">range</span>\n     <li><span class=\"dfn-paneled\" id=\"3fcc582f\">shadow root</span>\n     <li><span class=\"dfn-paneled\" id=\"8f378588\">shadow-including ancestor</span>\n     <li><span class=\"dfn-paneled\" id=\"fd32e3c9\">shadow-including descendant</span>\n     <li><span class=\"dfn-paneled\" id=\"3d6a3d36\">shadow-including inclusive ancestor</span>\n     <li><span class=\"dfn-paneled\" id=\"fefa5851\">shadow-including tree order</span>\n     <li><span class=\"dfn-paneled\" id=\"936c50ab\">start</span>\n     <li><span class=\"dfn-paneled\" id=\"6c88f67e\">start node</span>\n     <li><span class=\"dfn-paneled\" id=\"683b1507\">start offset</span>\n     <li><span class=\"dfn-paneled\" id=\"c9f15d91\">substring data</span>\n     <li><span class=\"dfn-paneled\" id=\"347e8fe9\">url</span>\n    </ul>\n   <li>\n    <a data-link-type=\"biblio\">[ENCODING]</a> defines the following terms:\n    <ul>\n     <li><span class=\"dfn-paneled\" id=\"a3033be5\">utf-8 decode without bom</span>\n    </ul>\n   <li>\n    <a data-link-type=\"biblio\">[FETCH]</a> defines the following terms:\n    <ul>\n     <li><span class=\"dfn-paneled\" id=\"55213b5b\">request</span>\n    </ul>\n   <li>\n    <a data-link-type=\"biblio\">[HTML]</a> defines the following terms:\n    <ul>\n     <li><span class=\"dfn-paneled\" id=\"fe2a6718\">HTMLAudioElement</span>\n     <li><span class=\"dfn-paneled\" id=\"10e25f42\">HTMLIFrameElement</span>\n     <li><span class=\"dfn-paneled\" id=\"c5891539\">HTMLImageElement</span>\n     <li><span class=\"dfn-paneled\" id=\"cc59b66b\">HTMLMeterElement</span>\n     <li><span class=\"dfn-paneled\" id=\"59ce5887\">HTMLObjectElement</span>\n     <li><span class=\"dfn-paneled\" id=\"fcadc50c\">HTMLProgressElement</span>\n     <li><span class=\"dfn-paneled\" id=\"ec4838d8\">HTMLScriptElement</span>\n     <li><span class=\"dfn-paneled\" id=\"aa8746c3\">HTMLStyleElement</span>\n     <li><span class=\"dfn-paneled\" id=\"f57f330b\">HTMLVideoElement</span>\n     <li><span class=\"dfn-paneled\" id=\"78492a07\">HashChangeEvent</span>\n     <li><span class=\"dfn-paneled\" id=\"cc549724\">Location</span>\n     <li><span class=\"dfn-paneled\" id=\"35972864\">active document</span>\n     <li><span class=\"dfn-paneled\" id=\"3c75104d\">apply the history step</span>\n     <li><span class=\"dfn-paneled\" id=\"1c1db69e\">apply the push/replace history step</span>\n     <li><span class=\"dfn-paneled\" id=\"f8434dee\">being rendered</span>\n     <li><span class=\"dfn-paneled\" id=\"3b2ff63e\">browsing context</span>\n     <li><span class=\"dfn-paneled\" id=\"b0b49d3c\">browsing context set</span>\n     <li><span class=\"dfn-paneled\" id=\"07ad3048\">create navigation params by fetching</span>\n     <li><span class=\"dfn-paneled\" id=\"65393af9\">document</span>\n     <li><span class=\"dfn-paneled\" id=\"092de955\">document state</span>\n     <li><span class=\"dfn-paneled\" id=\"7f118064\">finalize a cross-document navigation</span>\n     <li><span class=\"dfn-paneled\" id=\"40a1c717\">group</span>\n     <li><span class=\"dfn-paneled\" id=\"2895d75d\">initiator origin</span>\n     <li><span class=\"dfn-paneled\" id=\"d4dbbbf0\">language</span>\n     <li><span class=\"dfn-paneled\" id=\"b07164ad\">multiple</span>\n     <li><span class=\"dfn-paneled\" id=\"2594e562\">navigate</span>\n     <li><span class=\"dfn-paneled\" id=\"fffd9ca9\">navigate to a fragment</span>\n     <li><span class=\"dfn-paneled\" id=\"4437edc6\">navigation params</span>\n     <li><span class=\"dfn-paneled\" id=\"13dd6cae\">node navigable</span>\n     <li><span class=\"dfn-paneled\" id=\"086e3aff\">origin</span>\n     <li><span class=\"dfn-paneled\" id=\"1bba3db7\">parent</span>\n     <li><span class=\"dfn-paneled\" id=\"8b87b428\">restore persisted state</span>\n     <li><span class=\"dfn-paneled\" id=\"7393da89\">same origin</span>\n     <li><span class=\"dfn-paneled\" id=\"3f2e859c\">scroll to the fragment</span>\n     <li><span class=\"dfn-paneled\" id=\"85188fb3\">select</span>\n     <li><span class=\"dfn-paneled\" id=\"c3ae9e6a\">serializes as void</span>\n     <li><span class=\"dfn-paneled\" id=\"8a051c9f\">try to scroll to the fragment</span>\n     <li><span class=\"dfn-paneled\" id=\"5c1d019b\">update document for history step application</span>\n     <li><span class=\"dfn-paneled\" id=\"34d2343e\">user navigation involvement</span>\n    </ul>\n   <li>\n    <a data-link-type=\"biblio\">[INFRA]</a> defines the following terms:\n    <ul>\n     <li><span class=\"dfn-paneled\" id=\"53275e46\">append</span>\n     <li><span class=\"dfn-paneled\" id=\"2d5a2765\">ascii string</span>\n     <li><span class=\"dfn-paneled\" id=\"77b4c09a\">assert</span>\n     <li><span class=\"dfn-paneled\" id=\"7b0d918d\">break</span>\n     <li><span class=\"dfn-paneled\" id=\"915aff5e\">code point</span>\n     <li><span class=\"dfn-paneled\" id=\"4ef39030\">code point length</span>\n     <li><span class=\"dfn-paneled\" id=\"bb1f9628\">code point substring</span>\n     <li><span class=\"dfn-paneled\" id=\"cfd05055\">code point substring by positions</span>\n     <li><span class=\"dfn-paneled\" id=\"b8906bbb\">code point substring to the end of the string</span>\n     <li><span class=\"dfn-paneled\" id=\"4a3bf5fb\">concatenate</span>\n     <li><span class=\"dfn-paneled\" id=\"f937b7b6\">continue</span>\n     <li><span class=\"dfn-paneled\" id=\"03afaf9c\">empty</span>\n     <li><span class=\"dfn-paneled\" id=\"9c05f1bf\">ends with</span>\n     <li><span class=\"dfn-paneled\" id=\"16d07e10\">for each</span>\n     <li><span class=\"dfn-paneled\" id=\"f052b1ea\">html namespace</span>\n     <li><span class=\"dfn-paneled\" id=\"860300d4\">implementation-defined</span>\n     <li><span class=\"dfn-paneled\" id=\"0fa357c3\">length</span>\n     <li><span class=\"dfn-paneled\" id=\"649608b9\">list</span>\n     <li><span class=\"dfn-paneled\" id=\"75bee4d5\">position variable</span>\n     <li><span class=\"dfn-paneled\" id=\"0204d188\">size</span>\n     <li><span class=\"dfn-paneled\" id=\"54627f47\">starts with</span>\n     <li><span class=\"dfn-paneled\" id=\"7a3dbdb1\">strictly split a string</span>\n     <li><span class=\"dfn-paneled\" id=\"0698d556\">string</span>\n     <li><span class=\"dfn-paneled\" id=\"984221ca\">struct</span>\n    </ul>\n   <li>\n    <a data-link-type=\"biblio\">[MIMESNIFF]</a> defines the following terms:\n    <ul>\n     <li><span class=\"dfn-paneled\" id=\"7c195f8b\">essence</span>\n     <li><span class=\"dfn-paneled\" id=\"16785ec4\">mime type</span>\n    </ul>\n   <li>\n    <a data-link-type=\"biblio\">[URL]</a> defines the following terms:\n    <ul>\n     <li><span class=\"dfn-paneled\" id=\"ed948033\">fragment</span>\n     <li><span class=\"dfn-paneled\" id=\"79fa146b\">fragment percent-encode set</span>\n     <li><span class=\"dfn-paneled\" id=\"8f69ce41\">percent-decode</span>\n     <li><span class=\"dfn-paneled\" id=\"dcffbccd\">url</span>\n     <li><span class=\"dfn-paneled\" id=\"4bb788fe\">url code point</span>\n    </ul>\n   <li>\n    <a data-link-type=\"biblio\">[WEBIDL]</a> defines the following terms:\n    <ul>\n     <li><span class=\"dfn-paneled\" id=\"889e932f\">Exposed</span>\n     <li><span class=\"dfn-paneled\" id=\"a5c91173\">SameObject</span>\n    </ul>\n  </ul>\n  <h2 class=\"no-num no-ref heading settled\" id=\"references\"><span class=\"content\">References</span><a class=\"self-link\" href=\"#references\"></a></h2>\n  <h3 class=\"no-num no-ref heading settled\" id=\"normative\"><span class=\"content\">Normative References</span><a class=\"self-link\" href=\"#normative\"></a></h3>\n  <dl>\n   <dt id=\"biblio-css-cascade-5\">[CSS-CASCADE-5]\n   <dd>Elika Etemad; Miriam Suzanne; Tab Atkins Jr.. <a href=\"https://drafts.csswg.org/css-cascade-5/\"><cite>CSS Cascading and Inheritance Level 5</cite></a>. URL: <a href=\"https://drafts.csswg.org/css-cascade-5/\">https://drafts.csswg.org/css-cascade-5/</a>\n   <dt id=\"biblio-css-display-3\">[CSS-DISPLAY-3]\n   <dd>Elika Etemad; Tab Atkins Jr.. <a href=\"https://drafts.csswg.org/css-display/\"><cite>CSS Display Module Level 3</cite></a>. URL: <a href=\"https://drafts.csswg.org/css-display/\">https://drafts.csswg.org/css-display/</a>\n   <dt id=\"biblio-css-display-4\">[CSS-DISPLAY-4]\n   <dd><a href=\"https://drafts.csswg.org/css-display-4/\"><cite>CSS Display Module Level 4</cite></a>. Editor's Draft. URL: <a href=\"https://drafts.csswg.org/css-display-4/\">https://drafts.csswg.org/css-display-4/</a>\n   <dt id=\"biblio-cssom-view-1\">[CSSOM-VIEW-1]\n   <dd>Simon Pieters. <a href=\"https://drafts.csswg.org/cssom-view/\"><cite>CSSOM View Module</cite></a>. URL: <a href=\"https://drafts.csswg.org/cssom-view/\">https://drafts.csswg.org/cssom-view/</a>\n   <dt id=\"biblio-document-policy\">[DOCUMENT-POLICY]\n   <dd>Ian Clelland. <a href=\"https://wicg.github.io/document-policy\"><cite>Document Policy</cite></a>. ED. URL: <a href=\"https://wicg.github.io/document-policy\">https://wicg.github.io/document-policy</a>\n   <dt id=\"biblio-dom\">[DOM]\n   <dd>Anne van Kesteren. <a href=\"https://dom.spec.whatwg.org/\"><cite>DOM Standard</cite></a>. Living Standard. URL: <a href=\"https://dom.spec.whatwg.org/\">https://dom.spec.whatwg.org/</a>\n   <dt id=\"biblio-encoding\">[ENCODING]\n   <dd>Anne van Kesteren. <a href=\"https://encoding.spec.whatwg.org/\"><cite>Encoding Standard</cite></a>. Living Standard. URL: <a href=\"https://encoding.spec.whatwg.org/\">https://encoding.spec.whatwg.org/</a>\n   <dt id=\"biblio-fetch\">[FETCH]\n   <dd>Anne van Kesteren. <a href=\"https://fetch.spec.whatwg.org/\"><cite>Fetch Standard</cite></a>. Living Standard. URL: <a href=\"https://fetch.spec.whatwg.org/\">https://fetch.spec.whatwg.org/</a>\n   <dt id=\"biblio-html\">[HTML]\n   <dd>Anne van Kesteren; et al. <a href=\"https://html.spec.whatwg.org/multipage/\"><cite>HTML Standard</cite></a>. Living Standard. URL: <a href=\"https://html.spec.whatwg.org/multipage/\">https://html.spec.whatwg.org/multipage/</a>\n   <dt id=\"biblio-infra\">[INFRA]\n   <dd>Anne van Kesteren; Domenic Denicola. <a href=\"https://infra.spec.whatwg.org/\"><cite>Infra Standard</cite></a>. Living Standard. URL: <a href=\"https://infra.spec.whatwg.org/\">https://infra.spec.whatwg.org/</a>\n   <dt id=\"biblio-mimesniff\">[MIMESNIFF]\n   <dd>Gordon P. Hemsley. <a href=\"https://mimesniff.spec.whatwg.org/\"><cite>MIME Sniffing Standard</cite></a>. Living Standard. URL: <a href=\"https://mimesniff.spec.whatwg.org/\">https://mimesniff.spec.whatwg.org/</a>\n   <dt id=\"biblio-rfc2119\">[RFC2119]\n   <dd>S. Bradner. <a href=\"https://datatracker.ietf.org/doc/html/rfc2119\"><cite>Key words for use in RFCs to Indicate Requirement Levels</cite></a>. March 1997. Best Current Practice. URL: <a href=\"https://datatracker.ietf.org/doc/html/rfc2119\">https://datatracker.ietf.org/doc/html/rfc2119</a>\n   <dt id=\"biblio-uax29\">[UAX29]\n   <dd>Josh Hadley. <a href=\"https://www.unicode.org/reports/tr29/tr29-43.html\"><cite>Unicode Text Segmentation</cite></a>. 16 August 2023. Unicode Standard Annex #29. URL: <a href=\"https://www.unicode.org/reports/tr29/tr29-43.html\">https://www.unicode.org/reports/tr29/tr29-43.html</a>\n   <dt id=\"biblio-url\">[URL]\n   <dd>Anne van Kesteren. <a href=\"https://url.spec.whatwg.org/\"><cite>URL Standard</cite></a>. Living Standard. URL: <a href=\"https://url.spec.whatwg.org/\">https://url.spec.whatwg.org/</a>\n   <dt id=\"biblio-uts10\">[UTS10]\n   <dd>Ken Whistler; Markus Scherer. <a href=\"https://www.unicode.org/reports/tr10/tr10-49.html\"><cite>Unicode Collation Algorithm</cite></a>. 5 September 2023. Unicode Technical Standard #10. URL: <a href=\"https://www.unicode.org/reports/tr10/tr10-49.html\">https://www.unicode.org/reports/tr10/tr10-49.html</a>\n   <dt id=\"biblio-webidl\">[WEBIDL]\n   <dd>Edgar Chen; Timothy Gu. <a href=\"https://webidl.spec.whatwg.org/\"><cite>Web IDL Standard</cite></a>. Living Standard. URL: <a href=\"https://webidl.spec.whatwg.org/\">https://webidl.spec.whatwg.org/</a>\n  </dl>\n  <h3 class=\"no-num no-ref heading settled\" id=\"informative\"><span class=\"content\">Informative References</span><a class=\"self-link\" href=\"#informative\"></a></h3>\n  <dl>\n   <dt id=\"biblio-bcp47\">[BCP47]\n   <dd>A. Phillips, Ed.; M. Davis, Ed.. <a href=\"https://www.rfc-editor.org/rfc/rfc5646\"><cite>Tags for Identifying Languages</cite></a>. September 2009. Best Current Practice. URL: <a href=\"https://www.rfc-editor.org/rfc/rfc5646\">https://www.rfc-editor.org/rfc/rfc5646</a>\n   <dt id=\"biblio-fetch-metadata\">[FETCH-METADATA]\n   <dd>Mike West. <a href=\"https://w3c.github.io/webappsec-fetch-metadata/\"><cite>Fetch Metadata Request Headers</cite></a>. WD. URL: <a href=\"https://w3c.github.io/webappsec-fetch-metadata/\">https://w3c.github.io/webappsec-fetch-metadata/</a>\n  </dl>\n  <h2 class=\"no-num no-ref heading settled\" id=\"idl-index\"><span class=\"content\">IDL Index</span><a class=\"self-link\" href=\"#idl-index\"></a></h2>\n<pre class=\"idl highlight def\">[<a class=\"idl-code\" data-link-type=\"extended-attribute\" href=\"https://webidl.spec.whatwg.org/#Exposed\"><c- g>Exposed</c-></a>=<c- n>Window</c->]\n<c- b>interface</c-> <a href=\"#fragmentdirective\"><code><c- g>FragmentDirective</c-></code></a> {\n};\n\n<c- b>partial</c-> <c- b>interface</c-> <a class=\"idl-code\" data-link-type=\"interface\" href=\"https://dom.spec.whatwg.org/#document\"><c- g>Document</c-></a> {\n    [<a class=\"idl-code\" data-link-type=\"extended-attribute\" href=\"https://webidl.spec.whatwg.org/#SameObject\"><c- g>SameObject</c-></a>] <c- b>readonly</c-> <c- b>attribute</c-> <a data-link-type=\"idl-name\" href=\"#fragmentdirective\"><c- n>FragmentDirective</c-></a> <a data-readonly data-type=\"FragmentDirective\" href=\"#dom-document-fragmentdirective\"><code><c- g>fragmentDirective</c-></code></a>;\n};\n\n</pre>\n  <h2 class=\"no-num no-ref heading settled\" id=\"issues-index\"><span class=\"content\">Issues Index</span><a class=\"self-link\" href=\"#issues-index\"></a></h2>\n  <div style=\"counter-reset:issue\">\n   <div class=\"issue\"> TODO: If a URL’s fragment ends with ':~:' (i.e. empty directive), this will return null which\n    is treated as the URL not specifying an explicit directive (and avoids clobbering an existing\n    one. But maybe in this case we should return the empty string? That way a page can explicitly\n    clear directives/highlights by navigating/pushState to '#:~:'. <a class=\"issue-return\" href=\"#issue-f4a5d96b\" title=\"Jump to section\">↵</a></div>\n   <div class=\"issue\"> What should be set as target if inside a shadow tree? <a href=\"https://github.com/WICG/scroll-to-text-fragment/issues/190\">#190</a> <a class=\"issue-return\" href=\"#issue-424a4e25\" title=\"Jump to section\">↵</a></div>\n   <div class=\"issue\"> These revealing algorithms currently wont work well since <var>target</var> could be an\n      ancestor or even the root document node. Issue <a href=\"https://github.com/WICG/scroll-to-text-fragment/issues/89\">#89</a> proposes\n      restricting matches to <code>contain:style layout</code> blocks which would resolve this\n      problem. <a class=\"issue-return\" href=\"#issue-10739530\" title=\"Jump to section\">↵</a></div>\n   <div class=\"issue\">Implementation note: Blink doesn’t currently set focus for text\n  fragments, it probably should? TODO: file crbug. <a class=\"issue-return\" href=\"#issue-e253a983\" title=\"Jump to section\">↵</a></div>\n   <div class=\"issue\"> This isn’t strictly true, Chrome\nallows this for same-origin initiators. Need to update the spec on this\npoint. <a href=\"https://github.com/WICG/scroll-to-text-fragment/issues/240\">[Issue #WICG/scroll-to-text-fragment#240]</a> <a class=\"issue-return\" href=\"#issue-35f490f0\" title=\"Jump to section\">↵</a></div>\n   <div class=\"issue\"> Is this valid to say in the HTML spec? <a class=\"issue-return\" href=\"#issue-0e1d8eda\" title=\"Jump to section\">↵</a></div>\n   <div class=\"issue\"> Need to decide how <code>force-load-at-top</code> interacts with the Navigation API. <a href=\"https://github.com/WICG/scroll-to-text-fragment/issues/242\">[Issue #WICG/scroll-to-text-fragment#242]</a> <a class=\"issue-return\" href=\"#issue-de0fed9d\" title=\"Jump to section\">↵</a></div>\n   <div class=\"issue\"> <a data-link-type=\"dfn\" href=\"https://dom.spec.whatwg.org/#concept-cd-data\">data</a> is not\ncorrect here since that’s the text data as it exists in the DOM. This\nalgorithm means to run over the text as rendered (and then convert back\nto Ranges in the DOM). <a href=\"https://github.com/WICG/scroll-to-text-fragment/issues/98\">[Issue #WICG/scroll-to-text-fragment#98]</a> <a class=\"issue-return\" href=\"#issue-96fe4755\" title=\"Jump to section\">↵</a></div>\n  </div>\n<script>/* Boilerplate: script-dfn-panel */\n\"use strict\";\n{\n    const dfnsJson = window.dfnsJson || {};\n\n    function genDfnPanel({dfnID, url, dfnText, refSections, external}) {\n        return mk.aside({\n            class: \"dfn-panel\",\n            id: `infopanel-for-${dfnID}`,\n            \"data-for\": dfnID,\n            \"aria-labelled-by\":`infopaneltitle-for-${dfnID}`,\n            },\n            mk.span({id:`infopaneltitle-for-${dfnID}`, style:\"display:none\"},\n                `Info about the '${dfnText}' ${external?\"external\":\"\"} reference.`),\n            mk.a({href:url}, url),\n            mk.b({}, \"Referenced in:\"),\n            mk.ul({},\n                ...refSections.map(section=>\n                    mk.li({},\n                        ...section.refs.map((ref, refI)=>\n                            [\n                                mk.a({\n                                    href: `#${ref.id}`\n                                    },\n                                    (refI == 0) ? section.title : `(${refI + 1})`\n                                ),\n                                \" \",\n                            ]\n                        ),\n                    ),\n                ),\n            ),\n        );\n    }\n\n    function genAllDfnPanels() {\n        for(const panelData of Object.values(window.dfnpanelData)) {\n            const dfnID = panelData.dfnID;\n            const dfn = document.getElementById(dfnID);\n            if(!dfn) {\n                console.log(`Can't find dfn#${dfnID}.`, panelData);\n            } else {\n                const panel = genDfnPanel(panelData);\n                append(document.body, panel);\n                insertDfnPopupAction(dfn, panel)\n            }\n        }\n    }\n\n    document.addEventListener(\"DOMContentLoaded\", ()=>{\n        genAllDfnPanels();\n\n        // Add popup behavior to all dfns to show the corresponding dfn-panel.\n        var dfns = queryAll('.dfn-paneled');\n        for(let dfn of dfns) { ; }\n\n        document.body.addEventListener(\"click\", (e) => {\n            // If not handled already, just hide all dfn panels.\n            hideAllDfnPanels();\n        });\n    })\n\n\n    function hideAllDfnPanels() {\n        // Turn off any currently \"on\" or \"activated\" panels.\n        queryAll(\".dfn-panel.on, .dfn-panel.activated\").forEach(el=>hideDfnPanel(el));\n    }\n\n    function showDfnPanel(dfnPanel, dfn) {\n        hideAllDfnPanels(); // Only display one at this time.\n        dfn.setAttribute(\"aria-expanded\", \"true\");\n        dfnPanel.classList.add(\"on\");\n        dfnPanel.style.left = \"5px\";\n        dfnPanel.style.top = \"0px\";\n        const panelRect = dfnPanel.getBoundingClientRect();\n        const panelWidth = panelRect.right - panelRect.left;\n        if (panelRect.right > document.body.scrollWidth) {\n            // Panel's overflowing the screen.\n            // Just drop it below the dfn and flip it rightward instead.\n            // This still wont' fix things if the screen is *really* wide,\n            // but fixing that's a lot harder without 'anchor()'.\n            dfnPanel.style.top = \"1.5em\";\n            dfnPanel.style.left = \"auto\";\n            dfnPanel.style.right = \"0px\";\n        }\n    }\n\n    function pinDfnPanel(dfnPanel) {\n        // Switch it to \"activated\" state, which pins it.\n        dfnPanel.classList.add(\"activated\");\n        dfnPanel.style.left = null;\n        dfnPanel.style.top = null;\n    }\n\n    function hideDfnPanel(dfnPanel, dfn) {\n        if(!dfn) {\n            dfn = document.getElementById(dfnPanel.getAttribute(\"data-for\"));\n        }\n        dfn.setAttribute(\"aria-expanded\", \"false\")\n        dfnPanel.classList.remove(\"on\");\n        dfnPanel.classList.remove(\"activated\");\n    }\n\n    function toggleDfnPanel(dfnPanel, dfn) {\n        if(dfnPanel.classList.contains(\"on\")) {\n            hideDfnPanel(dfnPanel, dfn);\n        } else {\n            showDfnPanel(dfnPanel, dfn);\n        }\n    }\n\n    function insertDfnPopupAction(dfn, dfnPanel) {\n        // Find dfn panel\n        const panelWrapper = document.createElement('span');\n        panelWrapper.appendChild(dfnPanel);\n        panelWrapper.style.position = \"relative\";\n        panelWrapper.style.height = \"0px\";\n        dfn.insertAdjacentElement(\"afterend\", panelWrapper);\n        dfn.setAttribute('role', 'button');\n        dfn.setAttribute('aria-expanded', 'false')\n        dfn.tabIndex = 0;\n        dfn.classList.add('has-dfn-panel');\n        dfn.addEventListener('click', (event) => {\n            showDfnPanel(dfnPanel, dfn);\n            event.stopPropagation();\n        });\n        dfn.addEventListener('keypress', (event) => {\n            const kc = event.keyCode;\n            // 32->Space, 13->Enter\n            if(kc == 32 || kc == 13) {\n                toggleDfnPanel(dfnPanel, dfn);\n                event.stopPropagation();\n                event.preventDefault();\n            }\n        });\n\n        dfnPanel.addEventListener('click', (event) => {\n            if (event.target.nodeName == 'A') {\n                pinDfnPanel(dfnPanel);\n            }\n            event.stopPropagation();\n        });\n\n        dfnPanel.addEventListener('keydown', (event) => {\n            if(event.keyCode == 27) { // Escape key\n                hideDfnPanel(dfnPanel, dfn);\n                event.stopPropagation();\n                event.preventDefault();\n            }\n        })\n    }\n}\n</script>\n<script>/* Boilerplate: script-dfn-panel */\n\"use strict\";\n{\n    const dfnsJson = window.dfnsJson || {};\n\n    function genDfnPanel({dfnID, url, dfnText, refSections, external}) {\n        return mk.aside({\n            class: \"dfn-panel\",\n            id: `infopanel-for-${dfnID}`,\n            \"data-for\": dfnID,\n            \"aria-labelled-by\":`infopaneltitle-for-${dfnID}`,\n            },\n            mk.span({id:`infopaneltitle-for-${dfnID}`, style:\"display:none\"},\n                `Info about the '${dfnText}' ${external?\"external\":\"\"} reference.`),\n            mk.a({href:url}, url),\n            mk.b({}, \"Referenced in:\"),\n            mk.ul({},\n                ...refSections.map(section=>\n                    mk.li({},\n                        ...section.refs.map((ref, refI)=>\n                            [\n                                mk.a({\n                                    href: `#${ref.id}`\n                                    },\n                                    (refI == 0) ? section.title : `(${refI + 1})`\n                                ),\n                                \" \",\n                            ]\n                        ),\n                    ),\n                ),\n            ),\n        );\n    }\n\n    function genAllDfnPanels() {\n        for(const panelData of Object.values(window.dfnpanelData)) {\n            const dfnID = panelData.dfnID;\n            const dfn = document.getElementById(dfnID);\n            if(!dfn) {\n                console.log(`Can't find dfn#${dfnID}.`, panelData);\n            } else {\n                const panel = genDfnPanel(panelData);\n                append(document.body, panel);\n                insertDfnPopupAction(dfn, panel)\n            }\n        }\n    }\n\n    document.addEventListener(\"DOMContentLoaded\", ()=>{\n        genAllDfnPanels();\n\n        // Add popup behavior to all dfns to show the corresponding dfn-panel.\n        var dfns = queryAll('.dfn-paneled');\n        for(let dfn of dfns) { ; }\n\n        document.body.addEventListener(\"click\", (e) => {\n            // If not handled already, just hide all dfn panels.\n            hideAllDfnPanels();\n        });\n    })\n\n\n    function hideAllDfnPanels() {\n        // Turn off any currently \"on\" or \"activated\" panels.\n        queryAll(\".dfn-panel.on, .dfn-panel.activated\").forEach(el=>hideDfnPanel(el));\n    }\n\n    function showDfnPanel(dfnPanel, dfn) {\n        hideAllDfnPanels(); // Only display one at this time.\n        dfn.setAttribute(\"aria-expanded\", \"true\");\n        dfnPanel.classList.add(\"on\");\n        dfnPanel.style.left = \"5px\";\n        dfnPanel.style.top = \"0px\";\n        const panelRect = dfnPanel.getBoundingClientRect();\n        const panelWidth = panelRect.right - panelRect.left;\n        if (panelRect.right > document.body.scrollWidth) {\n            // Panel's overflowing the screen.\n            // Just drop it below the dfn and flip it rightward instead.\n            // This still wont' fix things if the screen is *really* wide,\n            // but fixing that's a lot harder without 'anchor()'.\n            dfnPanel.style.top = \"1.5em\";\n            dfnPanel.style.left = \"auto\";\n            dfnPanel.style.right = \"0px\";\n        }\n    }\n\n    function pinDfnPanel(dfnPanel) {\n        // Switch it to \"activated\" state, which pins it.\n        dfnPanel.classList.add(\"activated\");\n        dfnPanel.style.left = null;\n        dfnPanel.style.top = null;\n    }\n\n    function hideDfnPanel(dfnPanel, dfn) {\n        if(!dfn) {\n            dfn = document.getElementById(dfnPanel.getAttribute(\"data-for\"));\n        }\n        dfn.setAttribute(\"aria-expanded\", \"false\")\n        dfnPanel.classList.remove(\"on\");\n        dfnPanel.classList.remove(\"activated\");\n    }\n\n    function toggleDfnPanel(dfnPanel, dfn) {\n        if(dfnPanel.classList.contains(\"on\")) {\n            hideDfnPanel(dfnPanel, dfn);\n        } else {\n            showDfnPanel(dfnPanel, dfn);\n        }\n    }\n\n    function insertDfnPopupAction(dfn, dfnPanel) {\n        // Find dfn panel\n        const panelWrapper = document.createElement('span');\n        panelWrapper.appendChild(dfnPanel);\n        panelWrapper.style.position = \"relative\";\n        panelWrapper.style.height = \"0px\";\n        dfn.insertAdjacentElement(\"afterend\", panelWrapper);\n        dfn.setAttribute('role', 'button');\n        dfn.setAttribute('aria-expanded', 'false')\n        dfn.tabIndex = 0;\n        dfn.classList.add('has-dfn-panel');\n        dfn.addEventListener('click', (event) => {\n            showDfnPanel(dfnPanel, dfn);\n            event.stopPropagation();\n        });\n        dfn.addEventListener('keypress', (event) => {\n            const kc = event.keyCode;\n            // 32->Space, 13->Enter\n            if(kc == 32 || kc == 13) {\n                toggleDfnPanel(dfnPanel, dfn);\n                event.stopPropagation();\n                event.preventDefault();\n            }\n        });\n\n        dfnPanel.addEventListener('click', (event) => {\n            if (event.target.nodeName == 'A') {\n                pinDfnPanel(dfnPanel);\n            }\n            event.stopPropagation();\n        });\n\n        dfnPanel.addEventListener('keydown', (event) => {\n            if(event.keyCode == 27) { // Escape key\n                hideDfnPanel(dfnPanel, dfn);\n                event.stopPropagation();\n                event.preventDefault();\n            }\n        })\n    }\n}\n</script>\n<script>/* Boilerplate: script-dfn-panel-json */\nwindow.dfnpanelData = {};\nwindow.dfnpanelData['9cd25054'] = {\"dfnID\": \"9cd25054\", \"url\": \"https://drafts.csswg.org/css-cascade-5/#computed-value\", \"dfnText\": \"computed value\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-computed-value\"}, {\"id\": \"ref-for-computed-value\\u2460\"}, {\"id\": \"ref-for-computed-value\\u2461\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['66498315'] = {\"dfnID\": \"66498315\", \"url\": \"https://drafts.csswg.org/css-display-3/#valdef-display-flex\", \"dfnText\": \"flex\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-valdef-display-flex\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['a555386f'] = {\"dfnID\": \"a555386f\", \"url\": \"https://drafts.csswg.org/css-display-3/#valdef-display-grid\", \"dfnText\": \"grid\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-valdef-display-grid\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['bb886fc6'] = {\"dfnID\": \"bb886fc6\", \"url\": \"https://drafts.csswg.org/css-display-4/#valdef-display-block\", \"dfnText\": \"block\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-valdef-display-block\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['e7f0dd6c'] = {\"dfnID\": \"e7f0dd6c\", \"url\": \"https://drafts.csswg.org/css-display-4/#propdef-display\", \"dfnText\": \"display\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-propdef-display\"}, {\"id\": \"ref-for-propdef-display\\u2460\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['607244fc'] = {\"dfnID\": \"607244fc\", \"url\": \"https://drafts.csswg.org/css-display-4/#valdef-display-flow-root\", \"dfnText\": \"flow-root\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-valdef-display-flow-root\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['96626f55'] = {\"dfnID\": \"96626f55\", \"url\": \"https://drafts.csswg.org/css-display-4/#valdef-display-list-item\", \"dfnText\": \"list-item\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-valdef-display-list-item\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['55e8f5de'] = {\"dfnID\": \"55e8f5de\", \"url\": \"https://drafts.csswg.org/css-display-4/#valdef-display-none\", \"dfnText\": \"none\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-valdef-display-none\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['abb2bed7'] = {\"dfnID\": \"abb2bed7\", \"url\": \"https://drafts.csswg.org/css-display-4/#valdef-display-table\", \"dfnText\": \"table\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-valdef-display-table\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['12f8fb07'] = {\"dfnID\": \"12f8fb07\", \"url\": \"https://drafts.csswg.org/css-display-4/#propdef-visibility\", \"dfnText\": \"visibility\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-propdef-visibility\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['6420cb11'] = {\"dfnID\": \"6420cb11\", \"url\": \"https://drafts.csswg.org/css-display-4/#valdef-visibility-visible\", \"dfnText\": \"visible\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-valdef-visibility-visible\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['2cbb079e'] = {\"dfnID\": \"2cbb079e\", \"url\": \"https://drafts.csswg.org/cssom-view-1/#scroll-a-target-into-view\", \"dfnText\": \"scroll a target into view\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-scroll-a-target-into-view\"}], \"title\": \"3.4.1. Invoking Text Directives\"}], \"external\": true};\nwindow.dfnpanelData['85394472'] = {\"dfnID\": \"85394472\", \"url\": \"https://dom.spec.whatwg.org/#document\", \"dfnText\": \"Document\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-document\"}, {\"id\": \"ref-for-document\\u2460\"}], \"title\": \"3.9. Feature Detectability\"}], \"external\": true};\nwindow.dfnpanelData['597088f0'] = {\"dfnID\": \"597088f0\", \"url\": \"https://dom.spec.whatwg.org/#text\", \"dfnText\": \"Text\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-text\"}, {\"id\": \"ref-for-text\\u2460\"}, {\"id\": \"ref-for-text\\u2461\"}, {\"id\": \"ref-for-text\\u2462\"}, {\"id\": \"ref-for-text\\u2463\"}, {\"id\": \"ref-for-text\\u2464\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['4fef809c'] = {\"dfnID\": \"4fef809c\", \"url\": \"https://dom.spec.whatwg.org/#concept-range-bp-after\", \"dfnText\": \"after\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-range-bp-after\"}, {\"id\": \"ref-for-concept-range-bp-after\\u2460\"}, {\"id\": \"ref-for-concept-range-bp-after\\u2461\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['8a3e6de2'] = {\"dfnID\": \"8a3e6de2\", \"url\": \"https://dom.spec.whatwg.org/#concept-range-bp\", \"dfnText\": \"boundary point\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-range-bp\"}, {\"id\": \"ref-for-concept-range-bp\\u2460\"}, {\"id\": \"ref-for-concept-range-bp\\u2461\"}, {\"id\": \"ref-for-concept-range-bp\\u2462\"}, {\"id\": \"ref-for-concept-range-bp\\u2463\"}, {\"id\": \"ref-for-concept-range-bp\\u2464\"}, {\"id\": \"ref-for-concept-range-bp\\u2465\"}, {\"id\": \"ref-for-concept-range-bp\\u2466\"}, {\"id\": \"ref-for-concept-range-bp\\u2467\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['8aac8409'] = {\"dfnID\": \"8aac8409\", \"url\": \"https://dom.spec.whatwg.org/#range-collapsed\", \"dfnText\": \"collapsed\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-range-collapsed\"}, {\"id\": \"ref-for-range-collapsed\\u2460\"}, {\"id\": \"ref-for-range-collapsed\\u2461\"}, {\"id\": \"ref-for-range-collapsed\\u2462\"}, {\"id\": \"ref-for-range-collapsed\\u2463\"}, {\"id\": \"ref-for-range-collapsed\\u2464\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['3f23ec71'] = {\"dfnID\": \"3f23ec71\", \"url\": \"https://dom.spec.whatwg.org/#concept-document-content-type\", \"dfnText\": \"content type\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-document-content-type\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": true};\nwindow.dfnpanelData['212ee1f7'] = {\"dfnID\": \"212ee1f7\", \"url\": \"https://dom.spec.whatwg.org/#concept-cd-data\", \"dfnText\": \"data\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-cd-data\"}, {\"id\": \"ref-for-concept-cd-data\\u2460\"}, {\"id\": \"ref-for-concept-cd-data\\u2461\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['cefd9ec1'] = {\"dfnID\": \"cefd9ec1\", \"url\": \"https://dom.spec.whatwg.org/#concept-doctype\", \"dfnText\": \"doctype\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-doctype\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['a973e0fe'] = {\"dfnID\": \"a973e0fe\", \"url\": \"https://dom.spec.whatwg.org/#concept-document\", \"dfnText\": \"document\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-document\"}], \"title\": \"3.3.2. Applying directives to a document\"}, {\"refs\": [{\"id\": \"ref-for-concept-document\\u2460\"}], \"title\": \"3.5.3. Search Timing\"}, {\"refs\": [{\"id\": \"ref-for-concept-document\\u2461\"}, {\"id\": \"ref-for-concept-document\\u2462\"}, {\"id\": \"ref-for-concept-document\\u2463\"}, {\"id\": \"ref-for-concept-document\\u2464\"}, {\"id\": \"ref-for-concept-document\\u2465\"}, {\"id\": \"ref-for-concept-document\\u2466\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}, {\"refs\": [{\"id\": \"ref-for-concept-document\\u2467\"}, {\"id\": \"ref-for-concept-document\\u2468\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}, {\"refs\": [{\"id\": \"ref-for-concept-document\\u2460\\u24ea\"}, {\"id\": \"ref-for-concept-document\\u2460\\u2460\"}], \"title\": \"3.8. Document Policy Integration\"}], \"external\": true};\nwindow.dfnpanelData['2f0ba72c'] = {\"dfnID\": \"2f0ba72c\", \"url\": \"https://dom.spec.whatwg.org/#document-element\", \"dfnText\": \"document element\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-document-element\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['27d9b7ea'] = {\"dfnID\": \"27d9b7ea\", \"url\": \"https://dom.spec.whatwg.org/#concept-element\", \"dfnText\": \"element\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-element\"}, {\"id\": \"ref-for-concept-element\\u2460\"}], \"title\": \"3.4.1. Invoking Text Directives\"}, {\"refs\": [{\"id\": \"ref-for-concept-element\\u2461\"}], \"title\": \"3.6. Navigating to a Text Fragment\"}, {\"refs\": [{\"id\": \"ref-for-concept-element\\u2462\"}, {\"id\": \"ref-for-concept-element\\u2463\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['5bbf7dec'] = {\"dfnID\": \"5bbf7dec\", \"url\": \"https://dom.spec.whatwg.org/#concept-range-end\", \"dfnText\": \"end\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-range-end\"}, {\"id\": \"ref-for-concept-range-end\\u2460\"}, {\"id\": \"ref-for-concept-range-end\\u2461\"}, {\"id\": \"ref-for-concept-range-end\\u2462\"}, {\"id\": \"ref-for-concept-range-end\\u2463\"}, {\"id\": \"ref-for-concept-range-end\\u2464\"}, {\"id\": \"ref-for-concept-range-end\\u2465\"}, {\"id\": \"ref-for-concept-range-end\\u2466\"}, {\"id\": \"ref-for-concept-range-end\\u2467\"}, {\"id\": \"ref-for-concept-range-end\\u2468\"}, {\"id\": \"ref-for-concept-range-end\\u2460\\u24ea\"}, {\"id\": \"ref-for-concept-range-end\\u2460\\u2460\"}, {\"id\": \"ref-for-concept-range-end\\u2460\\u2461\"}, {\"id\": \"ref-for-concept-range-end\\u2460\\u2462\"}, {\"id\": \"ref-for-concept-range-end\\u2460\\u2463\"}, {\"id\": \"ref-for-concept-range-end\\u2460\\u2464\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['3edd98b4'] = {\"dfnID\": \"3edd98b4\", \"url\": \"https://dom.spec.whatwg.org/#concept-range-end-node\", \"dfnText\": \"end node\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-range-end-node\"}], \"title\": \"3.4.1. Invoking Text Directives\"}, {\"refs\": [{\"id\": \"ref-for-concept-range-end-node\\u2460\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}, {\"refs\": [{\"id\": \"ref-for-concept-range-end-node\\u2461\"}, {\"id\": \"ref-for-concept-range-end-node\\u2462\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['203b148b'] = {\"dfnID\": \"203b148b\", \"url\": \"https://dom.spec.whatwg.org/#concept-range-end-offset\", \"dfnText\": \"end offset\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-range-end-offset\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['6fba6744'] = {\"dfnID\": \"6fba6744\", \"url\": \"https://dom.spec.whatwg.org/#concept-tree-following\", \"dfnText\": \"following\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-tree-following\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['5d233601'] = {\"dfnID\": \"5d233601\", \"url\": \"https://dom.spec.whatwg.org/#concept-documentfragment-host\", \"dfnText\": \"host\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-documentfragment-host\"}], \"title\": \"3.6. Navigating to a Text Fragment\"}], \"external\": true};\nwindow.dfnpanelData['5e8d5f81'] = {\"dfnID\": \"5e8d5f81\", \"url\": \"https://dom.spec.whatwg.org/#concept-node-length\", \"dfnText\": \"length\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-node-length\"}, {\"id\": \"ref-for-concept-node-length\\u2460\"}, {\"id\": \"ref-for-concept-node-length\\u2461\"}, {\"id\": \"ref-for-concept-node-length\\u2462\"}, {\"id\": \"ref-for-concept-node-length\\u2463\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['d462b34f'] = {\"dfnID\": \"d462b34f\", \"url\": \"https://dom.spec.whatwg.org/#boundary-point-node\", \"dfnText\": \"node\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-boundary-point-node\"}, {\"id\": \"ref-for-boundary-point-node\\u2460\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['5216e1a0'] = {\"dfnID\": \"5216e1a0\", \"url\": \"https://dom.spec.whatwg.org/#concept-node-document\", \"dfnText\": \"node document\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-node-document\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['c62cd7cf'] = {\"dfnID\": \"c62cd7cf\", \"url\": \"https://dom.spec.whatwg.org/#concept-document-origin\", \"dfnText\": \"origin\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-document-origin\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": true};\nwindow.dfnpanelData['d729a9ff'] = {\"dfnID\": \"d729a9ff\", \"url\": \"https://dom.spec.whatwg.org/#concept-tree-parent\", \"dfnText\": \"parent\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-tree-parent\"}], \"title\": \"3.4.1. Invoking Text Directives\"}, {\"refs\": [{\"id\": \"ref-for-concept-tree-parent\\u2460\"}], \"title\": \"3.6. Navigating to a Text Fragment\"}, {\"refs\": [{\"id\": \"ref-for-concept-tree-parent\\u2461\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['5afeceea'] = {\"dfnID\": \"5afeceea\", \"url\": \"https://dom.spec.whatwg.org/#parent-element\", \"dfnText\": \"parent element\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-parent-element\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['8044ee41'] = {\"dfnID\": \"8044ee41\", \"url\": \"https://dom.spec.whatwg.org/#concept-range\", \"dfnText\": \"range\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-range\"}, {\"id\": \"ref-for-concept-range\\u2460\"}, {\"id\": \"ref-for-concept-range\\u2461\"}, {\"id\": \"ref-for-concept-range\\u2462\"}, {\"id\": \"ref-for-concept-range\\u2463\"}, {\"id\": \"ref-for-concept-range\\u2464\"}, {\"id\": \"ref-for-concept-range\\u2465\"}, {\"id\": \"ref-for-concept-range\\u2466\"}, {\"id\": \"ref-for-concept-range\\u2467\"}], \"title\": \"3.4.1. Invoking Text Directives\"}, {\"refs\": [{\"id\": \"ref-for-concept-range\\u2468\"}, {\"id\": \"ref-for-concept-range\\u2460\\u24ea\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}, {\"refs\": [{\"id\": \"ref-for-concept-range\\u2460\\u2460\"}], \"title\": \"3.6. Navigating to a Text Fragment\"}, {\"refs\": [{\"id\": \"ref-for-concept-range\\u2460\\u2461\"}, {\"id\": \"ref-for-concept-range\\u2460\\u2462\"}, {\"id\": \"ref-for-concept-range\\u2460\\u2463\"}, {\"id\": \"ref-for-concept-range\\u2460\\u2464\"}, {\"id\": \"ref-for-concept-range\\u2460\\u2465\"}, {\"id\": \"ref-for-concept-range\\u2460\\u2466\"}, {\"id\": \"ref-for-concept-range\\u2460\\u2467\"}, {\"id\": \"ref-for-concept-range\\u2460\\u2468\"}, {\"id\": \"ref-for-concept-range\\u2461\\u24ea\"}, {\"id\": \"ref-for-concept-range\\u2461\\u2460\"}, {\"id\": \"ref-for-concept-range\\u2461\\u2461\"}, {\"id\": \"ref-for-concept-range\\u2461\\u2462\"}, {\"id\": \"ref-for-concept-range\\u2461\\u2463\"}, {\"id\": \"ref-for-concept-range\\u2461\\u2464\"}, {\"id\": \"ref-for-concept-range\\u2461\\u2465\"}, {\"id\": \"ref-for-concept-range\\u2461\\u2466\"}, {\"id\": \"ref-for-concept-range\\u2461\\u2467\"}, {\"id\": \"ref-for-concept-range\\u2461\\u2468\"}, {\"id\": \"ref-for-concept-range\\u2462\\u24ea\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['3fcc582f'] = {\"dfnID\": \"3fcc582f\", \"url\": \"https://dom.spec.whatwg.org/#concept-shadow-root\", \"dfnText\": \"shadow root\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-shadow-root\"}], \"title\": \"3.6. Navigating to a Text Fragment\"}], \"external\": true};\nwindow.dfnpanelData['8f378588'] = {\"dfnID\": \"8f378588\", \"url\": \"https://dom.spec.whatwg.org/#concept-shadow-including-ancestor\", \"dfnText\": \"shadow-including ancestor\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-shadow-including-ancestor\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['fd32e3c9'] = {\"dfnID\": \"fd32e3c9\", \"url\": \"https://dom.spec.whatwg.org/#concept-shadow-including-descendant\", \"dfnText\": \"shadow-including descendant\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-shadow-including-descendant\"}, {\"id\": \"ref-for-concept-shadow-including-descendant\\u2460\"}, {\"id\": \"ref-for-concept-shadow-including-descendant\\u2461\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['3d6a3d36'] = {\"dfnID\": \"3d6a3d36\", \"url\": \"https://dom.spec.whatwg.org/#concept-shadow-including-inclusive-ancestor\", \"dfnText\": \"shadow-including inclusive ancestor\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-shadow-including-inclusive-ancestor\"}], \"title\": \"3.6. Navigating to a Text Fragment\"}], \"external\": true};\nwindow.dfnpanelData['fefa5851'] = {\"dfnID\": \"fefa5851\", \"url\": \"https://dom.spec.whatwg.org/#concept-shadow-including-tree-order\", \"dfnText\": \"shadow-including tree order\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-shadow-including-tree-order\"}, {\"id\": \"ref-for-concept-shadow-including-tree-order\\u2460\"}, {\"id\": \"ref-for-concept-shadow-including-tree-order\\u2461\"}, {\"id\": \"ref-for-concept-shadow-including-tree-order\\u2462\"}, {\"id\": \"ref-for-concept-shadow-including-tree-order\\u2463\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['936c50ab'] = {\"dfnID\": \"936c50ab\", \"url\": \"https://dom.spec.whatwg.org/#concept-range-start\", \"dfnText\": \"start\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-range-start\"}, {\"id\": \"ref-for-concept-range-start\\u2460\"}, {\"id\": \"ref-for-concept-range-start\\u2461\"}, {\"id\": \"ref-for-concept-range-start\\u2462\"}, {\"id\": \"ref-for-concept-range-start\\u2463\"}, {\"id\": \"ref-for-concept-range-start\\u2464\"}, {\"id\": \"ref-for-concept-range-start\\u2465\"}, {\"id\": \"ref-for-concept-range-start\\u2466\"}, {\"id\": \"ref-for-concept-range-start\\u2467\"}, {\"id\": \"ref-for-concept-range-start\\u2468\"}, {\"id\": \"ref-for-concept-range-start\\u2460\\u24ea\"}, {\"id\": \"ref-for-concept-range-start\\u2460\\u2460\"}, {\"id\": \"ref-for-concept-range-start\\u2460\\u2461\"}, {\"id\": \"ref-for-concept-range-start\\u2460\\u2462\"}, {\"id\": \"ref-for-concept-range-start\\u2460\\u2463\"}, {\"id\": \"ref-for-concept-range-start\\u2460\\u2464\"}, {\"id\": \"ref-for-concept-range-start\\u2460\\u2465\"}, {\"id\": \"ref-for-concept-range-start\\u2460\\u2466\"}, {\"id\": \"ref-for-concept-range-start\\u2460\\u2467\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['6c88f67e'] = {\"dfnID\": \"6c88f67e\", \"url\": \"https://dom.spec.whatwg.org/#concept-range-start-node\", \"dfnText\": \"start node\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-range-start-node\"}], \"title\": \"3.4.1. Invoking Text Directives\"}, {\"refs\": [{\"id\": \"ref-for-concept-range-start-node\\u2460\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}, {\"refs\": [{\"id\": \"ref-for-concept-range-start-node\\u2461\"}, {\"id\": \"ref-for-concept-range-start-node\\u2462\"}, {\"id\": \"ref-for-concept-range-start-node\\u2463\"}, {\"id\": \"ref-for-concept-range-start-node\\u2464\"}, {\"id\": \"ref-for-concept-range-start-node\\u2465\"}, {\"id\": \"ref-for-concept-range-start-node\\u2466\"}, {\"id\": \"ref-for-concept-range-start-node\\u2467\"}, {\"id\": \"ref-for-concept-range-start-node\\u2468\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['683b1507'] = {\"dfnID\": \"683b1507\", \"url\": \"https://dom.spec.whatwg.org/#concept-range-start-offset\", \"dfnText\": \"start offset\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-range-start-offset\"}, {\"id\": \"ref-for-concept-range-start-offset\\u2460\"}, {\"id\": \"ref-for-concept-range-start-offset\\u2461\"}, {\"id\": \"ref-for-concept-range-start-offset\\u2462\"}, {\"id\": \"ref-for-concept-range-start-offset\\u2463\"}, {\"id\": \"ref-for-concept-range-start-offset\\u2464\"}, {\"id\": \"ref-for-concept-range-start-offset\\u2465\"}, {\"id\": \"ref-for-concept-range-start-offset\\u2466\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['c9f15d91'] = {\"dfnID\": \"c9f15d91\", \"url\": \"https://dom.spec.whatwg.org/#concept-cd-substring\", \"dfnText\": \"substring data\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-cd-substring\"}, {\"id\": \"ref-for-concept-cd-substring\\u2460\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['347e8fe9'] = {\"dfnID\": \"347e8fe9\", \"url\": \"https://dom.spec.whatwg.org/#concept-document-url\", \"dfnText\": \"url\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-document-url\"}], \"title\": \"3.3.1. Extracting the fragment directive\"}], \"external\": true};\nwindow.dfnpanelData['a3033be5'] = {\"dfnID\": \"a3033be5\", \"url\": \"https://encoding.spec.whatwg.org/#utf-8-decode-without-bom\", \"dfnText\": \"utf-8 decode without bom\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-utf-8-decode-without-bom\"}], \"title\": \"3.4. Text Directives\"}], \"external\": true};\nwindow.dfnpanelData['55213b5b'] = {\"dfnID\": \"55213b5b\", \"url\": \"https://fetch.spec.whatwg.org/#concept-request\", \"dfnText\": \"request\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-request\"}, {\"id\": \"ref-for-concept-request\\u2460\"}, {\"id\": \"ref-for-concept-request\\u2461\"}, {\"id\": \"ref-for-concept-request\\u2462\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": true};\nwindow.dfnpanelData['fe2a6718'] = {\"dfnID\": \"fe2a6718\", \"url\": \"https://html.spec.whatwg.org/multipage/media.html#htmlaudioelement\", \"dfnText\": \"HTMLAudioElement\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-htmlaudioelement\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['10e25f42'] = {\"dfnID\": \"10e25f42\", \"url\": \"https://html.spec.whatwg.org/multipage/iframe-embed-object.html#htmliframeelement\", \"dfnText\": \"HTMLIFrameElement\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-htmliframeelement\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['c5891539'] = {\"dfnID\": \"c5891539\", \"url\": \"https://html.spec.whatwg.org/multipage/embedded-content.html#htmlimageelement\", \"dfnText\": \"HTMLImageElement\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-htmlimageelement\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['cc59b66b'] = {\"dfnID\": \"cc59b66b\", \"url\": \"https://html.spec.whatwg.org/multipage/form-elements.html#htmlmeterelement\", \"dfnText\": \"HTMLMeterElement\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-htmlmeterelement\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['59ce5887'] = {\"dfnID\": \"59ce5887\", \"url\": \"https://html.spec.whatwg.org/multipage/iframe-embed-object.html#htmlobjectelement\", \"dfnText\": \"HTMLObjectElement\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-htmlobjectelement\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['fcadc50c'] = {\"dfnID\": \"fcadc50c\", \"url\": \"https://html.spec.whatwg.org/multipage/form-elements.html#htmlprogresselement\", \"dfnText\": \"HTMLProgressElement\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-htmlprogresselement\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['ec4838d8'] = {\"dfnID\": \"ec4838d8\", \"url\": \"https://html.spec.whatwg.org/multipage/scripting.html#htmlscriptelement\", \"dfnText\": \"HTMLScriptElement\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-htmlscriptelement\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['aa8746c3'] = {\"dfnID\": \"aa8746c3\", \"url\": \"https://html.spec.whatwg.org/multipage/semantics.html#htmlstyleelement\", \"dfnText\": \"HTMLStyleElement\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-htmlstyleelement\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['f57f330b'] = {\"dfnID\": \"f57f330b\", \"url\": \"https://html.spec.whatwg.org/multipage/media.html#htmlvideoelement\", \"dfnText\": \"HTMLVideoElement\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-htmlvideoelement\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['78492a07'] = {\"dfnID\": \"78492a07\", \"url\": \"https://html.spec.whatwg.org/multipage/nav-history-apis.html#hashchangeevent\", \"dfnText\": \"HashChangeEvent\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-hashchangeevent\"}], \"title\": \"3.3.1. Extracting the fragment directive\"}], \"external\": true};\nwindow.dfnpanelData['cc549724'] = {\"dfnID\": \"cc549724\", \"url\": \"https://html.spec.whatwg.org/multipage/nav-history-apis.html#location\", \"dfnText\": \"Location\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-location\"}], \"title\": \"3.3.1. Extracting the fragment directive\"}], \"external\": true};\nwindow.dfnpanelData['35972864'] = {\"dfnID\": \"35972864\", \"url\": \"https://html.spec.whatwg.org/multipage/document-sequences.html#nav-document\", \"dfnText\": \"active document\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-nav-document\"}], \"title\": \"3.3.1. Extracting the fragment directive\"}, {\"refs\": [{\"id\": \"ref-for-nav-document\\u2460\"}, {\"id\": \"ref-for-nav-document\\u2461\"}, {\"id\": \"ref-for-nav-document\\u2462\"}, {\"id\": \"ref-for-nav-document\\u2463\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": true};\nwindow.dfnpanelData['3c75104d'] = {\"dfnID\": \"3c75104d\", \"url\": \"https://html.spec.whatwg.org/multipage/browsing-the-web.html#apply-the-history-step\", \"dfnText\": \"apply the history step\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-apply-the-history-step\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": true};\nwindow.dfnpanelData['1c1db69e'] = {\"dfnID\": \"1c1db69e\", \"url\": \"https://html.spec.whatwg.org/multipage/browsing-the-web.html#apply-the-push%2Freplace-history-step\", \"dfnText\": \"apply the push/replace history step\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-apply-the-push%2Freplace-history-step\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": true};\nwindow.dfnpanelData['f8434dee'] = {\"dfnID\": \"f8434dee\", \"url\": \"https://html.spec.whatwg.org/multipage/rendering.html#being-rendered\", \"dfnText\": \"being rendered\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-being-rendered\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['3b2ff63e'] = {\"dfnID\": \"3b2ff63e\", \"url\": \"https://html.spec.whatwg.org/multipage/document-sequences.html#concept-document-bc\", \"dfnText\": \"browsing context\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-document-bc\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": true};\nwindow.dfnpanelData['b0b49d3c'] = {\"dfnID\": \"b0b49d3c\", \"url\": \"https://html.spec.whatwg.org/multipage/document-sequences.html#browsing-context-set\", \"dfnText\": \"browsing context set\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-browsing-context-set\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": true};\nwindow.dfnpanelData['07ad3048'] = {\"dfnID\": \"07ad3048\", \"url\": \"https://html.spec.whatwg.org/multipage/browsing-the-web.html#create-navigation-params-by-fetching\", \"dfnText\": \"create navigation params by fetching\", \"refSections\": [{\"refs\": [{\"id\": \"fc0e1ad00\"}], \"title\": \"3.3.1. Extracting the fragment directive\"}, {\"refs\": [{\"id\": \"ref-for-create-navigation-params-by-fetching\"}, {\"id\": \"ref-for-create-navigation-params-by-fetching\\u2460\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": true};\nwindow.dfnpanelData['65393af9'] = {\"dfnID\": \"65393af9\", \"url\": \"https://html.spec.whatwg.org/multipage/browsing-the-web.html#she-document\", \"dfnText\": \"document\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-she-document\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": true};\nwindow.dfnpanelData['092de955'] = {\"dfnID\": \"092de955\", \"url\": \"https://html.spec.whatwg.org/multipage/browsing-the-web.html#she-document-state\", \"dfnText\": \"document state\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-she-document-state\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": true};\nwindow.dfnpanelData['7f118064'] = {\"dfnID\": \"7f118064\", \"url\": \"https://html.spec.whatwg.org/multipage/browsing-the-web.html#finalize-a-cross-document-navigation\", \"dfnText\": \"finalize a cross-document navigation\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-finalize-a-cross-document-navigation\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": true};\nwindow.dfnpanelData['40a1c717'] = {\"dfnID\": \"40a1c717\", \"url\": \"https://html.spec.whatwg.org/multipage/browsers.html#tlbc-group\", \"dfnText\": \"group\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-tlbc-group\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": true};\nwindow.dfnpanelData['2895d75d'] = {\"dfnID\": \"2895d75d\", \"url\": \"https://html.spec.whatwg.org/multipage/browsing-the-web.html#document-state-initiator-origin\", \"dfnText\": \"initiator origin\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-document-state-initiator-origin\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": true};\nwindow.dfnpanelData['d4dbbbf0'] = {\"dfnID\": \"d4dbbbf0\", \"url\": \"https://html.spec.whatwg.org/multipage/dom.html#language\", \"dfnText\": \"language\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-language\"}, {\"id\": \"ref-for-language\\u2460\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['b07164ad'] = {\"dfnID\": \"b07164ad\", \"url\": \"https://html.spec.whatwg.org/multipage/form-elements.html#attr-select-multiple\", \"dfnText\": \"multiple\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-attr-select-multiple\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['2594e562'] = {\"dfnID\": \"2594e562\", \"url\": \"https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate\", \"dfnText\": \"navigate\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-navigate\"}], \"title\": \"3.3.1. Extracting the fragment directive\"}, {\"refs\": [{\"id\": \"ref-for-navigate\\u2460\"}, {\"id\": \"ref-for-navigate\\u2461\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": true};\nwindow.dfnpanelData['fffd9ca9'] = {\"dfnID\": \"fffd9ca9\", \"url\": \"https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate-fragid\", \"dfnText\": \"navigate to a fragment\", \"refSections\": [{\"refs\": [{\"id\": \"319d7c290\"}, {\"id\": \"319d7c291\"}], \"title\": \"3.3.1. Extracting the fragment directive\"}, {\"refs\": [{\"id\": \"319d7c292\"}], \"title\": \"3.4.1. Invoking Text Directives\"}, {\"refs\": [{\"id\": \"ref-for-navigate-fragid\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": true};\nwindow.dfnpanelData['4437edc6'] = {\"dfnID\": \"4437edc6\", \"url\": \"https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigation-params\", \"dfnText\": \"navigation params\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-navigation-params\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": true};\nwindow.dfnpanelData['13dd6cae'] = {\"dfnID\": \"13dd6cae\", \"url\": \"https://html.spec.whatwg.org/multipage/document-sequences.html#node-navigable\", \"dfnText\": \"node navigable\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-node-navigable\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": true};\nwindow.dfnpanelData['086e3aff'] = {\"dfnID\": \"086e3aff\", \"url\": \"https://html.spec.whatwg.org/multipage/browsers.html#concept-origin\", \"dfnText\": \"origin\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-origin\"}, {\"id\": \"ref-for-concept-origin\\u2460\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": true};\nwindow.dfnpanelData['1bba3db7'] = {\"dfnID\": \"1bba3db7\", \"url\": \"https://html.spec.whatwg.org/multipage/document-sequences.html#nav-parent\", \"dfnText\": \"parent\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-nav-parent\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": true};\nwindow.dfnpanelData['8b87b428'] = {\"dfnID\": \"8b87b428\", \"url\": \"https://html.spec.whatwg.org/multipage/browsing-the-web.html#restore-persisted-state\", \"dfnText\": \"restore persisted state\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-restore-persisted-state\"}], \"title\": \"3.5.5. Restricting Scroll on Load\"}, {\"refs\": [{\"id\": \"ref-for-restore-persisted-state\\u2460\"}], \"title\": \"3.8. Document Policy Integration\"}], \"external\": true};\nwindow.dfnpanelData['7393da89'] = {\"dfnID\": \"7393da89\", \"url\": \"https://html.spec.whatwg.org/multipage/browsers.html#same-origin\", \"dfnText\": \"same origin\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-same-origin\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": true};\nwindow.dfnpanelData['3f2e859c'] = {\"dfnID\": \"3f2e859c\", \"url\": \"https://html.spec.whatwg.org/multipage/browsing-the-web.html#scroll-to-the-fragment-identifier\", \"dfnText\": \"scroll to the fragment\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-scroll-to-the-fragment-identifier\"}, {\"id\": \"ref-for-scroll-to-the-fragment-identifier\\u2460\"}], \"title\": \"3.4.1. Invoking Text Directives\"}, {\"refs\": [{\"id\": \"ref-for-scroll-to-the-fragment-identifier\\u2461\"}, {\"id\": \"ref-for-scroll-to-the-fragment-identifier\\u2462\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}, {\"refs\": [{\"id\": \"ref-for-scroll-to-the-fragment-identifier\\u2463\"}], \"title\": \"3.8. Document Policy Integration\"}], \"external\": true};\nwindow.dfnpanelData['85188fb3'] = {\"dfnID\": \"85188fb3\", \"url\": \"https://html.spec.whatwg.org/multipage/form-elements.html#the-select-element\", \"dfnText\": \"select\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-the-select-element\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['c3ae9e6a'] = {\"dfnID\": \"c3ae9e6a\", \"url\": \"https://html.spec.whatwg.org/multipage/parsing.html#serializes-as-void\", \"dfnText\": \"serializes as void\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-serializes-as-void\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['8a051c9f'] = {\"dfnID\": \"8a051c9f\", \"url\": \"https://html.spec.whatwg.org/multipage/browsing-the-web.html#try-to-scroll-to-the-fragment\", \"dfnText\": \"try to scroll to the fragment\", \"refSections\": [{\"refs\": [{\"id\": \"44bd3acf0\"}], \"title\": \"3.4.1. Invoking Text Directives\"}, {\"refs\": [{\"id\": \"ref-for-try-to-scroll-to-the-fragment\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}, {\"refs\": [{\"id\": \"ref-for-try-to-scroll-to-the-fragment\\u2460\"}], \"title\": \"3.7. Indicating The Text Match\"}], \"external\": true};\nwindow.dfnpanelData['5c1d019b'] = {\"dfnID\": \"5c1d019b\", \"url\": \"https://html.spec.whatwg.org/multipage/browsing-the-web.html#update-document-for-history-step-application\", \"dfnText\": \"update document for history step application\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-update-document-for-history-step-application\"}], \"title\": \"3.3.2. Applying directives to a document\"}, {\"refs\": [{\"id\": \"ref-for-update-document-for-history-step-application\\u2460\"}, {\"id\": \"ref-for-update-document-for-history-step-application\\u2461\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}, {\"refs\": [{\"id\": \"ref-for-update-document-for-history-step-application\\u2462\"}], \"title\": \"3.5.5. Restricting Scroll on Load\"}], \"external\": true};\nwindow.dfnpanelData['34d2343e'] = {\"dfnID\": \"34d2343e\", \"url\": \"https://html.spec.whatwg.org/multipage/browsing-the-web.html#user-navigation-involvement\", \"dfnText\": \"user navigation involvement\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-user-navigation-involvement\"}, {\"id\": \"ref-for-user-navigation-involvement\\u2460\"}, {\"id\": \"ref-for-user-navigation-involvement\\u2461\"}, {\"id\": \"ref-for-user-navigation-involvement\\u2462\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": true};\nwindow.dfnpanelData['53275e46'] = {\"dfnID\": \"53275e46\", \"url\": \"https://infra.spec.whatwg.org/#list-append\", \"dfnText\": \"append\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-list-append\"}], \"title\": \"3.4. Text Directives\"}, {\"refs\": [{\"id\": \"ref-for-list-append\\u2460\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['2d5a2765'] = {\"dfnID\": \"2d5a2765\", \"url\": \"https://infra.spec.whatwg.org/#ascii-string\", \"dfnText\": \"ascii string\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-ascii-string\"}], \"title\": \"3.3.1. Extracting the fragment directive\"}, {\"refs\": [{\"id\": \"ref-for-ascii-string\\u2460\"}, {\"id\": \"ref-for-ascii-string\\u2461\"}, {\"id\": \"ref-for-ascii-string\\u2462\"}], \"title\": \"3.4. Text Directives\"}], \"external\": true};\nwindow.dfnpanelData['77b4c09a'] = {\"dfnID\": \"77b4c09a\", \"url\": \"https://infra.spec.whatwg.org/#assert\", \"dfnText\": \"assert\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-assert\"}, {\"id\": \"ref-for-assert\\u2460\"}, {\"id\": \"ref-for-assert\\u2461\"}], \"title\": \"3.4. Text Directives\"}, {\"refs\": [{\"id\": \"ref-for-assert\\u2462\"}, {\"id\": \"ref-for-assert\\u2463\"}, {\"id\": \"ref-for-assert\\u2464\"}, {\"id\": \"ref-for-assert\\u2465\"}, {\"id\": \"ref-for-assert\\u2466\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['7b0d918d'] = {\"dfnID\": \"7b0d918d\", \"url\": \"https://infra.spec.whatwg.org/#iteration-break\", \"dfnText\": \"break\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-iteration-break\"}, {\"id\": \"ref-for-iteration-break\\u2460\"}, {\"id\": \"ref-for-iteration-break\\u2461\"}, {\"id\": \"ref-for-iteration-break\\u2462\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['915aff5e'] = {\"dfnID\": \"915aff5e\", \"url\": \"https://infra.spec.whatwg.org/#code-point\", \"dfnText\": \"code point\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-code-point\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['4ef39030'] = {\"dfnID\": \"4ef39030\", \"url\": \"https://infra.spec.whatwg.org/#string-code-point-length\", \"dfnText\": \"code point length\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-string-code-point-length\"}], \"title\": \"3.3.1. Extracting the fragment directive\"}, {\"refs\": [{\"id\": \"ref-for-string-code-point-length\\u2460\"}], \"title\": \"3.4. Text Directives\"}], \"external\": true};\nwindow.dfnpanelData['bb1f9628'] = {\"dfnID\": \"bb1f9628\", \"url\": \"https://infra.spec.whatwg.org/#code-point-substring\", \"dfnText\": \"code point substring\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-code-point-substring\"}], \"title\": \"3.4. Text Directives\"}], \"external\": true};\nwindow.dfnpanelData['cfd05055'] = {\"dfnID\": \"cfd05055\", \"url\": \"https://infra.spec.whatwg.org/#code-point-substring-by-positions\", \"dfnText\": \"code point substring by positions\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-code-point-substring-by-positions\"}], \"title\": \"3.3.1. Extracting the fragment directive\"}], \"external\": true};\nwindow.dfnpanelData['b8906bbb'] = {\"dfnID\": \"b8906bbb\", \"url\": \"https://infra.spec.whatwg.org/#code-point-substring-to-the-end-of-the-string\", \"dfnText\": \"code point substring to the end of the string\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-code-point-substring-to-the-end-of-the-string\"}], \"title\": \"3.3.1. Extracting the fragment directive\"}, {\"refs\": [{\"id\": \"ref-for-code-point-substring-to-the-end-of-the-string\\u2460\"}, {\"id\": \"ref-for-code-point-substring-to-the-end-of-the-string\\u2461\"}], \"title\": \"3.4. Text Directives\"}], \"external\": true};\nwindow.dfnpanelData['4a3bf5fb'] = {\"dfnID\": \"4a3bf5fb\", \"url\": \"https://infra.spec.whatwg.org/#string-concatenate\", \"dfnText\": \"concatenate\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-string-concatenate\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['f937b7b6'] = {\"dfnID\": \"f937b7b6\", \"url\": \"https://infra.spec.whatwg.org/#iteration-continue\", \"dfnText\": \"continue\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-iteration-continue\"}], \"title\": \"3.4. Text Directives\"}, {\"refs\": [{\"id\": \"ref-for-iteration-continue\\u2460\"}, {\"id\": \"ref-for-iteration-continue\\u2461\"}, {\"id\": \"ref-for-iteration-continue\\u2462\"}, {\"id\": \"ref-for-iteration-continue\\u2463\"}, {\"id\": \"ref-for-iteration-continue\\u2464\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['03afaf9c'] = {\"dfnID\": \"03afaf9c\", \"url\": \"https://infra.spec.whatwg.org/#list-empty\", \"dfnText\": \"empty\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-list-empty\"}, {\"id\": \"ref-for-list-empty\\u2460\"}, {\"id\": \"ref-for-list-empty\\u2461\"}], \"title\": \"3.4. Text Directives\"}], \"external\": true};\nwindow.dfnpanelData['9c05f1bf'] = {\"dfnID\": \"9c05f1bf\", \"url\": \"https://infra.spec.whatwg.org/#string-ends-with\", \"dfnText\": \"ends with\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-string-ends-with\"}], \"title\": \"3.4. Text Directives\"}], \"external\": true};\nwindow.dfnpanelData['16d07e10'] = {\"dfnID\": \"16d07e10\", \"url\": \"https://infra.spec.whatwg.org/#list-iterate\", \"dfnText\": \"for each\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-list-iterate\"}], \"title\": \"3.4. Text Directives\"}, {\"refs\": [{\"id\": \"ref-for-list-iterate\\u2460\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['f052b1ea'] = {\"dfnID\": \"f052b1ea\", \"url\": \"https://infra.spec.whatwg.org/#html-namespace\", \"dfnText\": \"html namespace\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-html-namespace\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['860300d4'] = {\"dfnID\": \"860300d4\", \"url\": \"https://infra.spec.whatwg.org/#implementation-defined\", \"dfnText\": \"implementation-defined\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-implementation-defined\"}], \"title\": \"3.4.1. Invoking Text Directives\"}], \"external\": true};\nwindow.dfnpanelData['0fa357c3'] = {\"dfnID\": \"0fa357c3\", \"url\": \"https://infra.spec.whatwg.org/#string-length\", \"dfnText\": \"length\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-string-length\"}, {\"id\": \"ref-for-string-length\\u2460\"}, {\"id\": \"ref-for-string-length\\u2461\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['649608b9'] = {\"dfnID\": \"649608b9\", \"url\": \"https://infra.spec.whatwg.org/#list\", \"dfnText\": \"list\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-list\"}], \"title\": \"3.3.2. Applying directives to a document\"}, {\"refs\": [{\"id\": \"ref-for-list\\u2460\"}, {\"id\": \"ref-for-list\\u2461\"}], \"title\": \"3.4. Text Directives\"}, {\"refs\": [{\"id\": \"ref-for-list\\u2462\"}], \"title\": \"3.4.1. Invoking Text Directives\"}, {\"refs\": [{\"id\": \"ref-for-list\\u2463\"}, {\"id\": \"ref-for-list\\u2464\"}, {\"id\": \"ref-for-list\\u2465\"}, {\"id\": \"ref-for-list\\u2466\"}, {\"id\": \"ref-for-list\\u2467\"}, {\"id\": \"ref-for-list\\u2468\"}, {\"id\": \"ref-for-list\\u2460\\u24ea\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": true};\nwindow.dfnpanelData['75bee4d5'] = {\"dfnID\": \"75bee4d5\", \"url\": \"https://infra.spec.whatwg.org/#string-position-variable\", \"dfnText\": \"position variable\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-string-position-variable\"}], \"title\": \"3.3.1. Extracting the fragment directive\"}], \"external\": true};\nwindow.dfnpanelData['0204d188'] = {\"dfnID\": \"0204d188\", \"url\": \"https://infra.spec.whatwg.org/#list-size\", \"dfnText\": \"size\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-list-size\"}, {\"id\": \"ref-for-list-size\\u2460\"}, {\"id\": \"ref-for-list-size\\u2461\"}], \"title\": \"3.4. Text Directives\"}], \"external\": true};\nwindow.dfnpanelData['54627f47'] = {\"dfnID\": \"54627f47\", \"url\": \"https://infra.spec.whatwg.org/#string-starts-with\", \"dfnText\": \"starts with\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-string-starts-with\"}, {\"id\": \"ref-for-string-starts-with\\u2460\"}], \"title\": \"3.4. Text Directives\"}], \"external\": true};\nwindow.dfnpanelData['7a3dbdb1'] = {\"dfnID\": \"7a3dbdb1\", \"url\": \"https://infra.spec.whatwg.org/#strictly-split\", \"dfnText\": \"strictly split a string\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-strictly-split\"}, {\"id\": \"ref-for-strictly-split\\u2460\"}], \"title\": \"3.4. Text Directives\"}], \"external\": true};\nwindow.dfnpanelData['0698d556'] = {\"dfnID\": \"0698d556\", \"url\": \"https://infra.spec.whatwg.org/#string\", \"dfnText\": \"string\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-string\"}], \"title\": \"3.3.3. Fragment directive grammar\"}, {\"refs\": [{\"id\": \"ref-for-string\\u2460\"}, {\"id\": \"ref-for-string\\u2461\"}, {\"id\": \"ref-for-string\\u2462\"}, {\"id\": \"ref-for-string\\u2463\"}], \"title\": \"3.4. Text Directives\"}, {\"refs\": [{\"id\": \"ref-for-string\\u2464\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}, {\"refs\": [{\"id\": \"ref-for-string\\u2465\"}, {\"id\": \"ref-for-string\\u2466\"}, {\"id\": \"ref-for-string\\u2467\"}], \"title\": \"3.6.2. Word Boundaries\"}], \"external\": true};\nwindow.dfnpanelData['984221ca'] = {\"dfnID\": \"984221ca\", \"url\": \"https://infra.spec.whatwg.org/#struct\", \"dfnText\": \"struct\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-struct\"}], \"title\": \"3.4. Text Directives\"}], \"external\": true};\nwindow.dfnpanelData['7c195f8b'] = {\"dfnID\": \"7c195f8b\", \"url\": \"https://mimesniff.spec.whatwg.org/#mime-type-essence\", \"dfnText\": \"essence\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-mime-type-essence\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": true};\nwindow.dfnpanelData['16785ec4'] = {\"dfnID\": \"16785ec4\", \"url\": \"https://mimesniff.spec.whatwg.org/#mime-type\", \"dfnText\": \"mime type\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-mime-type\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": true};\nwindow.dfnpanelData['ed948033'] = {\"dfnID\": \"ed948033\", \"url\": \"https://url.spec.whatwg.org/#concept-url-fragment\", \"dfnText\": \"fragment\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-url-fragment\"}], \"title\": \"3.3. The Fragment Directive\"}, {\"refs\": [{\"id\": \"ref-for-concept-url-fragment\\u2460\"}, {\"id\": \"ref-for-concept-url-fragment\\u2461\"}], \"title\": \"3.3.1. Extracting the fragment directive\"}], \"external\": true};\nwindow.dfnpanelData['79fa146b'] = {\"dfnID\": \"79fa146b\", \"url\": \"https://url.spec.whatwg.org/#fragment-percent-encode-set\", \"dfnText\": \"fragment percent-encode set\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-fragment-percent-encode-set\"}], \"title\": \"3.4. Text Directives\"}], \"external\": true};\nwindow.dfnpanelData['8f69ce41'] = {\"dfnID\": \"8f69ce41\", \"url\": \"https://url.spec.whatwg.org/#string-percent-decode\", \"dfnText\": \"percent-decode\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-string-percent-decode\"}], \"title\": \"3.4. Text Directives\"}], \"external\": true};\nwindow.dfnpanelData['dcffbccd'] = {\"dfnID\": \"dcffbccd\", \"url\": \"https://url.spec.whatwg.org/#concept-url\", \"dfnText\": \"url\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-concept-url\"}, {\"id\": \"ref-for-concept-url\\u2460\"}, {\"id\": \"ref-for-concept-url\\u2461\"}], \"title\": \"3.3.1. Extracting the fragment directive\"}], \"external\": true};\nwindow.dfnpanelData['4bb788fe'] = {\"dfnID\": \"4bb788fe\", \"url\": \"https://url.spec.whatwg.org/#url-code-points\", \"dfnText\": \"url code point\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-url-code-points\"}, {\"id\": \"ref-for-url-code-points\\u2460\"}], \"title\": \"3.3.3. Fragment directive grammar\"}], \"external\": true};\nwindow.dfnpanelData['889e932f'] = {\"dfnID\": \"889e932f\", \"url\": \"https://webidl.spec.whatwg.org/#Exposed\", \"dfnText\": \"Exposed\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-Exposed\"}], \"title\": \"3.9. Feature Detectability\"}], \"external\": true};\nwindow.dfnpanelData['a5c91173'] = {\"dfnID\": \"a5c91173\", \"url\": \"https://webidl.spec.whatwg.org/#SameObject\", \"dfnText\": \"SameObject\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-SameObject\"}], \"title\": \"3.9. Feature Detectability\"}], \"external\": true};\nwindow.dfnpanelData['fragment-directive'] = {\"dfnID\": \"fragment-directive\", \"url\": \"#fragment-directive\", \"dfnText\": \"fragment directive\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-fragment-directive\"}], \"title\": \"3.2. Syntax\"}, {\"refs\": [{\"id\": \"ref-for-fragment-directive\\u2460\"}, {\"id\": \"ref-for-fragment-directive\\u2461\"}], \"title\": \"3.3. The Fragment Directive\"}, {\"refs\": [{\"id\": \"ref-for-fragment-directive\\u2462\"}, {\"id\": \"ref-for-fragment-directive\\u2463\"}, {\"id\": \"ref-for-fragment-directive\\u2464\"}, {\"id\": \"ref-for-fragment-directive\\u2465\"}], \"title\": \"3.3.1. Extracting the fragment directive\"}, {\"refs\": [{\"id\": \"ref-for-fragment-directive\\u2466\"}], \"title\": \"3.3.2. Applying directives to a document\"}, {\"refs\": [{\"id\": \"ref-for-fragment-directive\\u2467\"}, {\"id\": \"ref-for-fragment-directive\\u2468\"}, {\"id\": \"ref-for-fragment-directive\\u2460\\u24ea\"}], \"title\": \"3.7.1. URLs in UA features\"}, {\"refs\": [{\"id\": \"ref-for-fragment-directive\\u2460\\u2460\"}], \"title\": \"3.7.1.1. Location Bar\"}, {\"refs\": [{\"id\": \"ref-for-fragment-directive\\u2460\\u2461\"}, {\"id\": \"ref-for-fragment-directive\\u2460\\u2462\"}], \"title\": \"3.7.1.2. Bookmarks\"}, {\"refs\": [{\"id\": \"ref-for-fragment-directive\\u2460\\u2463\"}], \"title\": \"3.7.1.3. Sharing\"}], \"external\": false};\nwindow.dfnpanelData['fragment-directive-delimiter'] = {\"dfnID\": \"fragment-directive-delimiter\", \"url\": \"#fragment-directive-delimiter\", \"dfnText\": \"fragment directive delimiter\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-fragment-directive-delimiter\"}], \"title\": \"3.3. The Fragment Directive\"}, {\"refs\": [{\"id\": \"ref-for-fragment-directive-delimiter\\u2460\"}, {\"id\": \"ref-for-fragment-directive-delimiter\\u2461\"}, {\"id\": \"ref-for-fragment-directive-delimiter\\u2462\"}, {\"id\": \"ref-for-fragment-directive-delimiter\\u2463\"}], \"title\": \"3.3.1. Extracting the fragment directive\"}], \"external\": false};\nwindow.dfnpanelData['directives'] = {\"dfnID\": \"directives\", \"url\": \"#directives\", \"dfnText\": \"directives\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-directives\"}], \"title\": \"3.4. Text Directives\"}], \"external\": false};\nwindow.dfnpanelData['directive-state'] = {\"dfnID\": \"directive-state\", \"url\": \"#directive-state\", \"dfnText\": \"directive state\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-directive-state\"}, {\"id\": \"ref-for-directive-state\\u2460\"}, {\"id\": \"ref-for-directive-state\\u2461\"}, {\"id\": \"ref-for-directive-state\\u2462\"}, {\"id\": \"ref-for-directive-state\\u2463\"}, {\"id\": \"ref-for-directive-state\\u2464\"}, {\"id\": \"ref-for-directive-state\\u2465\"}, {\"id\": \"ref-for-directive-state\\u2466\"}], \"title\": \"3.3.1. Extracting the fragment directive\"}], \"external\": false};\nwindow.dfnpanelData['directive-state-value'] = {\"dfnID\": \"directive-state-value\", \"url\": \"#directive-state-value\", \"dfnText\": \"value\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-directive-state-value\"}, {\"id\": \"ref-for-directive-state-value\\u2460\"}, {\"id\": \"ref-for-directive-state-value\\u2461\"}, {\"id\": \"ref-for-directive-state-value\\u2462\"}, {\"id\": \"ref-for-directive-state-value\\u2463\"}], \"title\": \"3.3.1. Extracting the fragment directive\"}, {\"refs\": [{\"id\": \"ref-for-directive-state-value\\u2464\"}], \"title\": \"3.3.2. Applying directives to a document\"}], \"external\": false};\nwindow.dfnpanelData['she-directive-state'] = {\"dfnID\": \"she-directive-state\", \"url\": \"#she-directive-state\", \"dfnText\": \"directive state\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-she-directive-state\"}, {\"id\": \"ref-for-she-directive-state\\u2460\"}, {\"id\": \"ref-for-she-directive-state\\u2461\"}, {\"id\": \"ref-for-she-directive-state\\u2462\"}, {\"id\": \"ref-for-she-directive-state\\u2463\"}, {\"id\": \"ref-for-she-directive-state\\u2464\"}, {\"id\": \"ref-for-she-directive-state\\u2465\"}, {\"id\": \"ref-for-she-directive-state\\u2466\"}], \"title\": \"3.3.1. Extracting the fragment directive\"}, {\"refs\": [{\"id\": \"ref-for-she-directive-state\\u2467\"}, {\"id\": \"ref-for-she-directive-state\\u2468\"}, {\"id\": \"ref-for-she-directive-state\\u2460\\u24ea\"}, {\"id\": \"ref-for-she-directive-state\\u2460\\u2460\"}], \"title\": \"3.3.2. Applying directives to a document\"}], \"external\": false};\nwindow.dfnpanelData['remove-the-fragment-directive'] = {\"dfnID\": \"remove-the-fragment-directive\", \"url\": \"#remove-the-fragment-directive\", \"dfnText\": \"remove the fragment directive\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-remove-the-fragment-directive\"}, {\"id\": \"ref-for-remove-the-fragment-directive\\u2460\"}, {\"id\": \"ref-for-remove-the-fragment-directive\\u2461\"}, {\"id\": \"ref-for-remove-the-fragment-directive\\u2462\"}], \"title\": \"3.3.1. Extracting the fragment directive\"}], \"external\": false};\nwindow.dfnpanelData['document-pending-text-directives'] = {\"dfnID\": \"document-pending-text-directives\", \"url\": \"#document-pending-text-directives\", \"dfnText\": \"pending text directives\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-document-pending-text-directives\"}], \"title\": \"3.3.2. Applying directives to a document\"}, {\"refs\": [{\"id\": \"ref-for-document-pending-text-directives\\u2460\"}, {\"id\": \"ref-for-document-pending-text-directives\\u2461\"}, {\"id\": \"ref-for-document-pending-text-directives\\u2462\"}, {\"id\": \"ref-for-document-pending-text-directives\\u2463\"}, {\"id\": \"ref-for-document-pending-text-directives\\u2464\"}, {\"id\": \"ref-for-document-pending-text-directives\\u2465\"}, {\"id\": \"ref-for-document-pending-text-directives\\u2466\"}, {\"id\": \"ref-for-document-pending-text-directives\\u2467\"}, {\"id\": \"ref-for-document-pending-text-directives\\u2468\"}, {\"id\": \"ref-for-document-pending-text-directives\\u2460\\u24ea\"}], \"title\": \"3.4.1. Invoking Text Directives\"}, {\"refs\": [{\"id\": \"ref-for-document-pending-text-directives\\u2460\\u2460\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": false};\nwindow.dfnpanelData['fragmentdirectiveproduction'] = {\"dfnID\": \"fragmentdirectiveproduction\", \"url\": \"#fragmentdirectiveproduction\", \"dfnText\": \"FragmentDirective\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-fragmentdirectiveproduction\"}, {\"id\": \"ref-for-fragmentdirectiveproduction\\u2460\"}, {\"id\": \"ref-for-fragmentdirectiveproduction\\u2461\"}], \"title\": \"3.3.3. Fragment directive grammar\"}], \"external\": false};\nwindow.dfnpanelData['textdirective'] = {\"dfnID\": \"textdirective\", \"url\": \"#textdirective\", \"dfnText\": \"TextDirective\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-textdirective\"}, {\"id\": \"ref-for-textdirective\\u2460\"}, {\"id\": \"ref-for-textdirective\\u2461\"}], \"title\": \"3.3.3. Fragment directive grammar\"}], \"external\": false};\nwindow.dfnpanelData['unknowndirective'] = {\"dfnID\": \"unknowndirective\", \"url\": \"#unknowndirective\", \"dfnText\": \"UnknownDirective\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-unknowndirective\"}], \"title\": \"3.3.3. Fragment directive grammar\"}], \"external\": false};\nwindow.dfnpanelData['characterstring'] = {\"dfnID\": \"characterstring\", \"url\": \"#characterstring\", \"dfnText\": \"CharacterString\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-characterstring\"}, {\"id\": \"ref-for-characterstring\\u2460\"}], \"title\": \"3.3.3. Fragment directive grammar\"}], \"external\": false};\nwindow.dfnpanelData['explicitchar'] = {\"dfnID\": \"explicitchar\", \"url\": \"#explicitchar\", \"dfnText\": \"ExplicitChar\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-explicitchar\"}, {\"id\": \"ref-for-explicitchar\\u2460\"}], \"title\": \"3.3.3. Fragment directive grammar\"}], \"external\": false};\nwindow.dfnpanelData['validtextdirective'] = {\"dfnID\": \"validtextdirective\", \"url\": \"#validtextdirective\", \"dfnText\": \"ValidTextDirective\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-validtextdirective\"}], \"title\": \"3.3.3. Fragment directive grammar\"}], \"external\": false};\nwindow.dfnpanelData['textdirectiveparameters'] = {\"dfnID\": \"textdirectiveparameters\", \"url\": \"#textdirectiveparameters\", \"dfnText\": \"TextDirectiveParameters\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-textdirectiveparameters\"}], \"title\": \"3.3.3. Fragment directive grammar\"}], \"external\": false};\nwindow.dfnpanelData['textdirectiveprefix'] = {\"dfnID\": \"textdirectiveprefix\", \"url\": \"#textdirectiveprefix\", \"dfnText\": \"TextDirectivePrefix\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-textdirectiveprefix\"}], \"title\": \"3.3.3. Fragment directive grammar\"}], \"external\": false};\nwindow.dfnpanelData['textdirectivesuffix'] = {\"dfnID\": \"textdirectivesuffix\", \"url\": \"#textdirectivesuffix\", \"dfnText\": \"TextDirectiveSuffix\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-textdirectivesuffix\"}], \"title\": \"3.3.3. Fragment directive grammar\"}], \"external\": false};\nwindow.dfnpanelData['textdirectivestring'] = {\"dfnID\": \"textdirectivestring\", \"url\": \"#textdirectivestring\", \"dfnText\": \"TextDirectiveString\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-textdirectivestring\"}, {\"id\": \"ref-for-textdirectivestring\\u2460\"}, {\"id\": \"ref-for-textdirectivestring\\u2461\"}, {\"id\": \"ref-for-textdirectivestring\\u2462\"}], \"title\": \"3.3.3. Fragment directive grammar\"}], \"external\": false};\nwindow.dfnpanelData['textdirectiveexplicitchar'] = {\"dfnID\": \"textdirectiveexplicitchar\", \"url\": \"#textdirectiveexplicitchar\", \"dfnText\": \"TextDirectiveExplicitChar\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-textdirectiveexplicitchar\"}, {\"id\": \"ref-for-textdirectiveexplicitchar\\u2460\"}], \"title\": \"3.3.3. Fragment directive grammar\"}], \"external\": false};\nwindow.dfnpanelData['percentencodedbyte'] = {\"dfnID\": \"percentencodedbyte\", \"url\": \"#percentencodedbyte\", \"dfnText\": \"PercentEncodedByte\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-percentencodedbyte\"}, {\"id\": \"ref-for-percentencodedbyte\\u2460\"}], \"title\": \"3.3.3. Fragment directive grammar\"}], \"external\": false};\nwindow.dfnpanelData['text-directive'] = {\"dfnID\": \"text-directive\", \"url\": \"#text-directive\", \"dfnText\": \"text directive\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-text-directive\"}], \"title\": \"3.2. Syntax\"}, {\"refs\": [{\"id\": \"ref-for-text-directive\\u2460\"}], \"title\": \"3.3.2. Applying directives to a document\"}, {\"refs\": [{\"id\": \"ref-for-text-directive\\u2461\"}, {\"id\": \"ref-for-text-directive\\u2462\"}, {\"id\": \"ref-for-text-directive\\u2463\"}, {\"id\": \"ref-for-text-directive\\u2464\"}], \"title\": \"3.4. Text Directives\"}, {\"refs\": [{\"id\": \"ref-for-text-directive\\u2465\"}], \"title\": \"3.4.1. Invoking Text Directives\"}, {\"refs\": [{\"id\": \"ref-for-text-directive\\u2466\"}, {\"id\": \"ref-for-text-directive\\u2467\"}], \"title\": \"3.5.1. Motivation\"}, {\"refs\": [{\"id\": \"ref-for-text-directive\\u2468\"}], \"title\": \"3.5.3. Search Timing\"}, {\"refs\": [{\"id\": \"ref-for-text-directive\\u2460\\u24ea\"}], \"title\": \"3.6. Navigating to a Text Fragment\"}, {\"refs\": [{\"id\": \"ref-for-text-directive\\u2460\\u2460\"}, {\"id\": \"ref-for-text-directive\\u2460\\u2461\"}, {\"id\": \"ref-for-text-directive\\u2460\\u2462\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}, {\"refs\": [{\"id\": \"ref-for-text-directive\\u2460\\u2463\"}], \"title\": \"4. Generating Text Fragment Directives\"}, {\"refs\": [{\"id\": \"ref-for-text-directive\\u2460\\u2464\"}, {\"id\": \"ref-for-text-directive\\u2460\\u2465\"}, {\"id\": \"ref-for-text-directive\\u2460\\u2466\"}], \"title\": \"4.2. Use Context Only When Necessary\"}, {\"refs\": [{\"id\": \"ref-for-text-directive\\u2460\\u2467\"}, {\"id\": \"ref-for-text-directive\\u2460\\u2468\"}], \"title\": \"4.3. Determine If Fragment Id Is Needed\"}], \"external\": false};\nwindow.dfnpanelData['text-directive-start'] = {\"dfnID\": \"text-directive-start\", \"url\": \"#text-directive-start\", \"dfnText\": \"start\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-text-directive-start\"}, {\"id\": \"ref-for-text-directive-start\\u2460\"}], \"title\": \"3.4. Text Directives\"}, {\"refs\": [{\"id\": \"ref-for-text-directive-start\\u2461\"}, {\"id\": \"ref-for-text-directive-start\\u2462\"}, {\"id\": \"ref-for-text-directive-start\\u2463\"}, {\"id\": \"ref-for-text-directive-start\\u2464\"}, {\"id\": \"ref-for-text-directive-start\\u2465\"}, {\"id\": \"ref-for-text-directive-start\\u2466\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": false};\nwindow.dfnpanelData['text-directive-end'] = {\"dfnID\": \"text-directive-end\", \"url\": \"#text-directive-end\", \"dfnText\": \"end\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-text-directive-end\"}], \"title\": \"3.4. Text Directives\"}, {\"refs\": [{\"id\": \"ref-for-text-directive-end\\u2460\"}, {\"id\": \"ref-for-text-directive-end\\u2461\"}, {\"id\": \"ref-for-text-directive-end\\u2462\"}, {\"id\": \"ref-for-text-directive-end\\u2463\"}, {\"id\": \"ref-for-text-directive-end\\u2464\"}, {\"id\": \"ref-for-text-directive-end\\u2465\"}, {\"id\": \"ref-for-text-directive-end\\u2466\"}, {\"id\": \"ref-for-text-directive-end\\u2467\"}, {\"id\": \"ref-for-text-directive-end\\u2468\"}, {\"id\": \"ref-for-text-directive-end\\u2460\\u24ea\"}, {\"id\": \"ref-for-text-directive-end\\u2460\\u2460\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": false};\nwindow.dfnpanelData['text-directive-prefix'] = {\"dfnID\": \"text-directive-prefix\", \"url\": \"#text-directive-prefix\", \"dfnText\": \"prefix\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-text-directive-prefix\"}], \"title\": \"3.4. Text Directives\"}, {\"refs\": [{\"id\": \"ref-for-text-directive-prefix\\u2460\"}, {\"id\": \"ref-for-text-directive-prefix\\u2461\"}, {\"id\": \"ref-for-text-directive-prefix\\u2462\"}, {\"id\": \"ref-for-text-directive-prefix\\u2463\"}, {\"id\": \"ref-for-text-directive-prefix\\u2464\"}, {\"id\": \"ref-for-text-directive-prefix\\u2465\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": false};\nwindow.dfnpanelData['text-directive-suffix'] = {\"dfnID\": \"text-directive-suffix\", \"url\": \"#text-directive-suffix\", \"dfnText\": \"suffix\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-text-directive-suffix\"}], \"title\": \"3.4. Text Directives\"}, {\"refs\": [{\"id\": \"ref-for-text-directive-suffix\\u2460\"}, {\"id\": \"ref-for-text-directive-suffix\\u2461\"}, {\"id\": \"ref-for-text-directive-suffix\\u2462\"}, {\"id\": \"ref-for-text-directive-suffix\\u2463\"}, {\"id\": \"ref-for-text-directive-suffix\\u2464\"}, {\"id\": \"ref-for-text-directive-suffix\\u2465\"}, {\"id\": \"ref-for-text-directive-suffix\\u2466\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": false};\nwindow.dfnpanelData['percent-decode-a-text-directive-term'] = {\"dfnID\": \"percent-decode-a-text-directive-term\", \"url\": \"#percent-decode-a-text-directive-term\", \"dfnText\": \"percent-decode a text directive term\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-percent-decode-a-text-directive-term\"}, {\"id\": \"ref-for-percent-decode-a-text-directive-term\\u2460\"}, {\"id\": \"ref-for-percent-decode-a-text-directive-term\\u2461\"}, {\"id\": \"ref-for-percent-decode-a-text-directive-term\\u2462\"}], \"title\": \"3.4. Text Directives\"}], \"external\": false};\nwindow.dfnpanelData['parse-a-text-directive'] = {\"dfnID\": \"parse-a-text-directive\", \"url\": \"#parse-a-text-directive\", \"dfnText\": \"parse a text directive\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-parse-a-text-directive\"}], \"title\": \"3.4. Text Directives\"}], \"external\": false};\nwindow.dfnpanelData['parse-the-fragment-directive'] = {\"dfnID\": \"parse-the-fragment-directive\", \"url\": \"#parse-the-fragment-directive\", \"dfnText\": \"parse the fragment directive\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-parse-the-fragment-directive\"}], \"title\": \"3.3.2. Applying directives to a document\"}], \"external\": false};\nwindow.dfnpanelData['request-text-directive-user-activation'] = {\"dfnID\": \"request-text-directive-user-activation\", \"url\": \"#request-text-directive-user-activation\", \"dfnText\": \"text directive user activation\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-request-text-directive-user-activation\"}, {\"id\": \"ref-for-request-text-directive-user-activation\\u2460\"}, {\"id\": \"ref-for-request-text-directive-user-activation\\u2461\"}, {\"id\": \"ref-for-request-text-directive-user-activation\\u2462\"}, {\"id\": \"ref-for-request-text-directive-user-activation\\u2463\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": false};\nwindow.dfnpanelData['document-text-directive-user-activation'] = {\"dfnID\": \"document-text-directive-user-activation\", \"url\": \"#document-text-directive-user-activation\", \"dfnText\": \"text directive user activation\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-document-text-directive-user-activation\"}, {\"id\": \"ref-for-document-text-directive-user-activation\\u2460\"}, {\"id\": \"ref-for-document-text-directive-user-activation\\u2461\"}, {\"id\": \"ref-for-document-text-directive-user-activation\\u2462\"}, {\"id\": \"ref-for-document-text-directive-user-activation\\u2463\"}, {\"id\": \"ref-for-document-text-directive-user-activation\\u2464\"}, {\"id\": \"ref-for-document-text-directive-user-activation\\u2465\"}, {\"id\": \"ref-for-document-text-directive-user-activation\\u2466\"}, {\"id\": \"ref-for-document-text-directive-user-activation\\u2467\"}, {\"id\": \"ref-for-document-text-directive-user-activation\\u2468\"}, {\"id\": \"ref-for-document-text-directive-user-activation\\u2460\\u24ea\"}, {\"id\": \"ref-for-document-text-directive-user-activation\\u2460\\u2460\"}, {\"id\": \"ref-for-document-text-directive-user-activation\\u2460\\u2461\"}, {\"id\": \"ref-for-document-text-directive-user-activation\\u2460\\u2462\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": false};\nwindow.dfnpanelData['navigation-params-user-involvement'] = {\"dfnID\": \"navigation-params-user-involvement\", \"url\": \"#navigation-params-user-involvement\", \"dfnText\": \"user involvement\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-navigation-params-user-involvement\"}, {\"id\": \"ref-for-navigation-params-user-involvement\\u2460\"}, {\"id\": \"ref-for-navigation-params-user-involvement\\u2461\"}, {\"id\": \"ref-for-navigation-params-user-involvement\\u2462\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": false};\nwindow.dfnpanelData['text-directive-allowing-mime-type'] = {\"dfnID\": \"text-directive-allowing-mime-type\", \"url\": \"#text-directive-allowing-mime-type\", \"dfnText\": \"text directive allowing MIME type\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-text-directive-allowing-mime-type\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": false};\nwindow.dfnpanelData['check-if-a-text-directive-can-be-scrolled'] = {\"dfnID\": \"check-if-a-text-directive-can-be-scrolled\", \"url\": \"#check-if-a-text-directive-can-be-scrolled\", \"dfnText\": \"check if a text directive can be scrolled\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-check-if-a-text-directive-can-be-scrolled\"}, {\"id\": \"ref-for-check-if-a-text-directive-can-be-scrolled\\u2460\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": false};\nwindow.dfnpanelData['first-common-ancestor'] = {\"dfnID\": \"first-common-ancestor\", \"url\": \"#first-common-ancestor\", \"dfnText\": \"first common ancestor\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-first-common-ancestor\"}], \"title\": \"3.4.1. Invoking Text Directives\"}, {\"refs\": [{\"id\": \"ref-for-first-common-ancestor\\u2460\"}], \"title\": \"3.5.4. Restricting the Text Fragment\"}], \"external\": false};\nwindow.dfnpanelData['shadow-including-parent'] = {\"dfnID\": \"shadow-including-parent\", \"url\": \"#shadow-including-parent\", \"dfnText\": \"shadow-including parent\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-shadow-including-parent\"}], \"title\": \"3.6. Navigating to a Text Fragment\"}], \"external\": false};\nwindow.dfnpanelData['invoke-text-directives'] = {\"dfnID\": \"invoke-text-directives\", \"url\": \"#invoke-text-directives\", \"dfnText\": \"invoke text directives\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-invoke-text-directives\"}], \"title\": \"3.4.1. Invoking Text Directives\"}, {\"refs\": [{\"id\": \"ref-for-invoke-text-directives\\u2460\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": false};\nwindow.dfnpanelData['find-a-range-from-a-text-directive'] = {\"dfnID\": \"find-a-range-from-a-text-directive\", \"url\": \"#find-a-range-from-a-text-directive\", \"dfnText\": \"find a range from a text directive\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-find-a-range-from-a-text-directive\"}], \"title\": \"3.5.3. Search Timing\"}, {\"refs\": [{\"id\": \"ref-for-find-a-range-from-a-text-directive\\u2460\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": false};\nwindow.dfnpanelData['next-non-whitespace-position'] = {\"dfnID\": \"next-non-whitespace-position\", \"url\": \"#next-non-whitespace-position\", \"dfnText\": \"next\\nnon-whitespace position\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-next-non-whitespace-position\"}, {\"id\": \"ref-for-next-non-whitespace-position\\u2460\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": false};\nwindow.dfnpanelData['find-a-string-in-range'] = {\"dfnID\": \"find-a-string-in-range\", \"url\": \"#find-a-string-in-range\", \"dfnText\": \"find a string in range\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-find-a-string-in-range\"}, {\"id\": \"ref-for-find-a-string-in-range\\u2460\"}, {\"id\": \"ref-for-find-a-string-in-range\\u2461\"}, {\"id\": \"ref-for-find-a-string-in-range\\u2462\"}, {\"id\": \"ref-for-find-a-string-in-range\\u2463\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": false};\nwindow.dfnpanelData['search-invisible'] = {\"dfnID\": \"search-invisible\", \"url\": \"#search-invisible\", \"dfnText\": \"search invisible\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-search-invisible\"}, {\"id\": \"ref-for-search-invisible\\u2460\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": false};\nwindow.dfnpanelData['non-searchable-subtree'] = {\"dfnID\": \"non-searchable-subtree\", \"url\": \"#non-searchable-subtree\", \"dfnText\": \"non-searchable subtree\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-non-searchable-subtree\"}, {\"id\": \"ref-for-non-searchable-subtree\\u2460\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": false};\nwindow.dfnpanelData['visible-text-node'] = {\"dfnID\": \"visible-text-node\", \"url\": \"#visible-text-node\", \"dfnText\": \"visible text node\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-visible-text-node\"}, {\"id\": \"ref-for-visible-text-node\\u2460\"}, {\"id\": \"ref-for-visible-text-node\\u2461\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": false};\nwindow.dfnpanelData['has-block-level-display'] = {\"dfnID\": \"has-block-level-display\", \"url\": \"#has-block-level-display\", \"dfnText\": \"has block-level display\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-has-block-level-display\"}, {\"id\": \"ref-for-has-block-level-display\\u2460\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": false};\nwindow.dfnpanelData['nearest-block-ancestor'] = {\"dfnID\": \"nearest-block-ancestor\", \"url\": \"#nearest-block-ancestor\", \"dfnText\": \"nearest block ancestor\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-nearest-block-ancestor\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": false};\nwindow.dfnpanelData['find-a-range-from-a-node-list'] = {\"dfnID\": \"find-a-range-from-a-node-list\", \"url\": \"#find-a-range-from-a-node-list\", \"dfnText\": \"find a range from a node list\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-find-a-range-from-a-node-list\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": false};\nwindow.dfnpanelData['get-boundary-point-at-index'] = {\"dfnID\": \"get-boundary-point-at-index\", \"url\": \"#get-boundary-point-at-index\", \"dfnText\": \"get boundary point at index\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-get-boundary-point-at-index\"}, {\"id\": \"ref-for-get-boundary-point-at-index\\u2460\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}], \"external\": false};\nwindow.dfnpanelData['word-boundary'] = {\"dfnID\": \"word-boundary\", \"url\": \"#word-boundary\", \"dfnText\": \"word boundary\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-word-boundary\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}, {\"refs\": [{\"id\": \"ref-for-word-boundary\\u2460\"}], \"title\": \"3.6.2. Word Boundaries\"}], \"external\": false};\nwindow.dfnpanelData['locale'] = {\"dfnID\": \"locale\", \"url\": \"#locale\", \"dfnText\": \"locale\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-locale\"}, {\"id\": \"ref-for-locale\\u2460\"}], \"title\": \"3.6.2. Word Boundaries\"}], \"external\": false};\nwindow.dfnpanelData['word-bounded'] = {\"dfnID\": \"word-bounded\", \"url\": \"#word-bounded\", \"dfnText\": \"word bounded\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-word-bounded\"}], \"title\": \"3.6.2. Word Boundaries\"}], \"external\": false};\nwindow.dfnpanelData['is-at-a-word-boundary'] = {\"dfnID\": \"is-at-a-word-boundary\", \"url\": \"#is-at-a-word-boundary\", \"dfnText\": \"is at a word boundary\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-is-at-a-word-boundary\"}, {\"id\": \"ref-for-is-at-a-word-boundary\\u2460\"}], \"title\": \"3.6.1. Finding Ranges in a Document\"}, {\"refs\": [{\"id\": \"ref-for-is-at-a-word-boundary\\u2461\"}, {\"id\": \"ref-for-is-at-a-word-boundary\\u2462\"}], \"title\": \"3.6.2. Word Boundaries\"}], \"external\": false};\nwindow.dfnpanelData['fragmentdirective'] = {\"dfnID\": \"fragmentdirective\", \"url\": \"#fragmentdirective\", \"dfnText\": \"FragmentDirective\", \"refSections\": [{\"refs\": [{\"id\": \"ref-for-fragmentdirective\"}], \"title\": \"3.9. Feature Detectability\"}], \"external\": false};\n</script>\n<script>/* Boilerplate: script-dom-helper */\nfunction query(sel) { return document.querySelector(sel); }\n\nfunction queryAll(sel) { return [...document.querySelectorAll(sel)]; }\n\nfunction iter(obj) {\n\tif(!obj) return [];\n\tvar it = obj[Symbol.iterator];\n\tif(it) return it;\n\treturn Object.entries(obj);\n}\n\nfunction mk(tagname, attrs, ...children) {\n\tconst el = document.createElement(tagname);\n\tfor(const [k,v] of iter(attrs)) {\n\t\tif(k.slice(0,3) == \"_on\") {\n\t\t\tconst eventName = k.slice(3);\n\t\t\tel.addEventListener(eventName, v);\n\t\t} else if(k[0] == \"_\") {\n\t\t\t// property, not attribute\n\t\t\tel[k.slice(1)] = v;\n\t\t} else {\n\t\t\tif(v === false || v == null) {\n        continue;\n      } else if(v === true) {\n        el.setAttribute(k, \"\");\n        continue;\n      } else {\n  \t\t\tel.setAttribute(k, v);\n      }\n\t\t}\n\t}\n\tappend(el, children);\n\treturn el;\n}\n\n/* Create shortcuts for every known HTML element */\n[\n  \"a\",\n  \"abbr\",\n  \"acronym\",\n  \"address\",\n  \"applet\",\n  \"area\",\n  \"article\",\n  \"aside\",\n  \"audio\",\n  \"b\",\n  \"base\",\n  \"basefont\",\n  \"bdo\",\n  \"big\",\n  \"blockquote\",\n  \"body\",\n  \"br\",\n  \"button\",\n  \"canvas\",\n  \"caption\",\n  \"center\",\n  \"cite\",\n  \"code\",\n  \"col\",\n  \"colgroup\",\n  \"datalist\",\n  \"dd\",\n  \"del\",\n  \"details\",\n  \"dfn\",\n  \"dialog\",\n  \"div\",\n  \"dl\",\n  \"dt\",\n  \"em\",\n  \"embed\",\n  \"fieldset\",\n  \"figcaption\",\n  \"figure\",\n  \"font\",\n  \"footer\",\n  \"form\",\n  \"frame\",\n  \"frameset\",\n  \"head\",\n  \"header\",\n  \"h1\",\n  \"h2\",\n  \"h3\",\n  \"h4\",\n  \"h5\",\n  \"h6\",\n  \"hr\",\n  \"html\",\n  \"i\",\n  \"iframe\",\n  \"img\",\n  \"input\",\n  \"ins\",\n  \"kbd\",\n  \"label\",\n  \"legend\",\n  \"li\",\n  \"link\",\n  \"main\",\n  \"map\",\n  \"mark\",\n  \"meta\",\n  \"meter\",\n  \"nav\",\n  \"nobr\",\n  \"noscript\",\n  \"object\",\n  \"ol\",\n  \"optgroup\",\n  \"option\",\n  \"output\",\n  \"p\",\n  \"param\",\n  \"pre\",\n  \"progress\",\n  \"q\",\n  \"s\",\n  \"samp\",\n  \"script\",\n  \"section\",\n  \"select\",\n  \"small\",\n  \"source\",\n  \"span\",\n  \"strike\",\n  \"strong\",\n  \"style\",\n  \"sub\",\n  \"summary\",\n  \"sup\",\n  \"table\",\n  \"tbody\",\n  \"td\",\n  \"template\",\n  \"textarea\",\n  \"tfoot\",\n  \"th\",\n  \"thead\",\n  \"time\",\n  \"title\",\n  \"tr\",\n  \"u\",\n  \"ul\",\n  \"var\",\n  \"video\",\n  \"wbr\",\n  \"xmp\",\n].forEach(tagname=>{\n\tmk[tagname] = (...args) => mk(tagname, ...args);\n});\n\nfunction* nodesFromChildList(children) {\n\tfor(const child of children.flat(Infinity)) {\n\t\tif(child instanceof Node) {\n\t\t\tyield child;\n\t\t} else {\n\t\t\tyield new Text(child);\n\t\t}\n\t}\n}\nfunction append(el, ...children) {\n\tfor(const child of nodesFromChildList(children)) {\n\t\tif(el instanceof Node) el.appendChild(child);\n\t\telse el.push(child);\n\t}\n\treturn el;\n}\n\nfunction insertAfter(el, ...children) {\n\tfor(const child of nodesFromChildList(children)) {\n\t\tel.parentNode.insertBefore(child, el.nextSibling);\n\t}\n\treturn el;\n}\n\nfunction clearContents(el) {\n\tel.innerHTML = \"\";\n\treturn el;\n}\n\nfunction parseHTML(markup) {\n\tif(markup.toLowerCase().trim().indexOf('<!doctype') === 0) {\n\t\tconst doc = document.implementation.createHTMLDocument(\"\");\n\t\tdoc.documentElement.innerHTML = markup;\n\t\treturn doc;\n\t} else {\n\t\tconst el = mk.template({});\n\t\tel.innerHTML = markup;\n\t\treturn el.content;\n\t}\n}\n</script>\n<script>/* Boilerplate: script-var-click-highlighting */\n/*\nColor-choosing design:\n\nColors are ordered by goodness.\nEach color has a usage count (initially zero).\nEach variable has a last-used color.\n\n* If the var has a last-used color, and that color's usage is 0,\n    return that color.\n* Otherwise, return the lowest-indexed color with the lowest usage.\n    Increment the color's usage and set it as the last-used color\n    for that var.\n* On unclicking, decrement usage of the color.\n*/\n\"use strict\";\n{\n    document.addEventListener(\"click\", e=>{\n        if(e.target.nodeName == \"VAR\") {\n            highlightSameAlgoVars(e.target);\n        }\n    });\n    const indexCounts = new Map();\n    const indexNames = new Map();\n    function highlightSameAlgoVars(v) {\n        // Find the algorithm container.\n        let algoContainer = null;\n        let searchEl = v;\n        while(algoContainer == null && searchEl != document.body) {\n            searchEl = searchEl.parentNode;\n            if(searchEl.hasAttribute(\"data-algorithm\")) {\n                algoContainer = searchEl;\n            }\n        }\n\n        // Not highlighting document-global vars,\n        // too likely to be unrelated.\n        if(algoContainer == null) return;\n\n        const algoName = algoContainer.getAttribute(\"data-algorithm\");\n        const varName = getVarName(v);\n        const addClass = !v.classList.contains(\"selected\");\n        let highlightClass = null;\n        if(addClass) {\n            const index = chooseHighlightIndex(algoName, varName);\n            indexCounts.get(algoName)[index] += 1;\n            indexNames.set(algoName+\"///\"+varName, index);\n            highlightClass = nameFromIndex(index);\n        } else {\n            const index = previousHighlightIndex(algoName, varName);\n            indexCounts.get(algoName)[index] -= 1;\n            highlightClass = nameFromIndex(index);\n        }\n\n        // Find all same-name vars, and toggle their class appropriately.\n        for(const el of algoContainer.querySelectorAll(\"var\")) {\n            if(getVarName(el) == varName) {\n                el.classList.toggle(\"selected\", addClass);\n                el.classList.toggle(highlightClass, addClass);\n            }\n        }\n    }\n    function getVarName(el) {\n        return el.textContent.replace(/(\\s|\\xa0)+/, \" \").trim();\n    }\n    function chooseHighlightIndex(algoName, varName) {\n        let indexes = null;\n        if(indexCounts.has(algoName)) {\n            indexes = indexCounts.get(algoName);\n        } else {\n            // 7 classes right now\n            indexes = [0,0,0,0,0,0,0];\n            indexCounts.set(algoName, indexes);\n        }\n\n        // If the element was recently unclicked,\n        // *and* that color is still unclaimed,\n        // give it back the same color.\n        const lastIndex = previousHighlightIndex(algoName, varName);\n        if(indexes[lastIndex] === 0) return lastIndex;\n\n        // Find the earliest index with the lowest count.\n        const minCount = Math.min.apply(null, indexes);\n        let index = null;\n        for(var i = 0; i < indexes.length; i++) {\n            if(indexes[i] == minCount) {\n                return i;\n            }\n        }\n    }\n    function previousHighlightIndex(algoName, varName) {\n        return indexNames.get(algoName+\"///\"+varName);\n    }\n    function nameFromIndex(index) {\n        return \"selected\" + index;\n    }\n}\n</script>\n<script>/* Boilerplate: script-wpt */\nlet wptPath = \"/scroll-to-text-fragment/\";\n\"use strict\";\n\ndocument.addEventListener(\"DOMContentLoaded\", async ()=>{\n    if(wptPath == \"/\") return;\n\n    const runsUrl = \"https://wpt.fyi/api/runs?label=master&label=stable&max-count=1&product=chrome&product=firefox&product=safari&product=edge\";\n    const runs = await (await fetch(runsUrl)).json();\n\n    const testResults = await (await fetch(\"https://wpt.fyi/api/search\", {\n        method:\"POST\",\n        headers:{\n            \"Content-Type\":\"application/json\",\n        },\n        body: JSON.stringify({\n            \"run_ids\": runs.map(x=>x.id),\n            \"query\": {\"path\": wptPath},\n        })\n    })).json();\n\n    const browsers = runs.map(x=>({name:x.browser_name, version:x.browser_version, passes:0, total: 0}));\n    const resultsFromPath = new Map(testResults.results.map(result=>{\n        const testPath = result.test;\n        const passes = result.legacy_status.map(x=>[x.passes, x.total]);\n        return [testPath, passes];\n    }));\n    const seenTests = new Set();\n    document.querySelectorAll(\".wpt-name\").forEach(nameEl=>{\n        const passData = resultsFromPath.get(\"/\" + nameEl.getAttribute(\"title\"));\n        if(!passData) {\n            console.log(\"Couldn't find test in results:\", nameEl);\n            return\n        }\n        const numTests = passData[0][1];\n        if(numTests > 1) {\n            nameEl.insertAdjacentElement(\"beforeend\",\n                el(\"small\", {}, ` (${numTests} tests)`));\n        }\n        if(passData == undefined) return;\n        const resultsEl = el(\"span\",{\"class\":\"wpt-results\"},\n            ...passData.map((p,i) => el(\"span\",\n            {\n                \"title\": `${browsers[i].name} ${p[0]}/${p[1]}`,\n                \"class\": \"wpt-result\",\n                \"style\": `background: conic-gradient(forestgreen ${p[0]/p[1]*360}deg, darkred 0deg);`,\n            })),\n        );\n        nameEl.insertAdjacentElement(\"afterend\", resultsEl);\n\n        // Only update the summary pass/total count if we haven't seen this\n        // test before, to support authors listing the same test multiple times\n        // in a spec.\n        if (!seenTests.has(nameEl.getAttribute(\"title\"))) {\n            seenTests.add(nameEl.getAttribute(\"title\"));\n            passData.forEach((p,i) => {\n                browsers[i].passes += p[0];\n                browsers[i].total += p[1];\n            });\n        }\n    });\n    const overview = document.querySelector(\".wpt-overview\");\n    if(overview) {\n        overview.appendChild(el('ul',{}, ...browsers.map(formatWptResult)));\n        document.head.appendChild(el('style', {},\n            `.wpt-overview ul { display: flex; flex-flow: row wrap; gap: .2em; justify-content: start; list-style: none; padding: 0; margin: 0;}\n             .wpt-overview li { padding: .25em 1em; color: black; text-align: center; }\n             .wpt-overview img { height: 1.5em; height: max(1.5em, 32px); background: transparent; }\n             .wpt-overview .browser { font-weight: bold; }\n             .wpt-overview .passes-none { background: #e57373; }\n             .wpt-overview .passes-hardly { background: #ffb74d; }\n             .wpt-overview .passes-a-few { background: #ffd54f; }\n             .wpt-overview .passes-half { background: #fff176; }\n             .wpt-overview .passes-lots { background: #dce775; }\n             .wpt-overview .passes-most { background: #aed581; }\n             .wpt-overview .passes-all { background: #81c784; }`));\n    }\n});\nfunction el(name, attrs, ...content) {\n    const x = document.createElement(name);\n    for(const [k,v] of Object.entries(attrs)) {\n        x.setAttribute(k, v);\n    }\n    for(let child of content) {\n        if(typeof child == \"string\") child = document.createTextNode(child);\n        try {\n        x.appendChild(child);\n        } catch(e) { console.log({x, child}); }\n    }\n    return x;\n}\nfunction formatWptResult({name, version, passes, total}) {\n    const passRate = passes/total;\n    let passClass = \"\";\n    if(passRate == 0)      passClass = \"passes-none\";\n    else if(passRate < .2) passClass = \"passes-hardly\";\n    else if(passRate < .4) passClass = \"passes-a-few\";\n    else if(passRate < .6) passClass = \"passes-half\";\n    else if(passRate < .8) passClass = \"passes-lots\";\n    else if(passRate < 1)  passClass = \"passes-most\";\n    else                   passClass = \"passes-all\";\n\n    name = name[0].toUpperCase() + name.slice(1);\n    const shortVersion = /^\\d+/.exec(version);\n    const icon = []\n\n    if(name == \"Chrome\") icon.push(el('img', {alt:\"\", src:\"https://wpt.fyi/static/chrome_64x64.png\"}));\n    if(name == \"Edge\") icon.push(el('img', {alt:\"\", src:\"https://wpt.fyi/static/edge_64x64.png\"}));\n    if(name == \"Safari\") icon.push(el('img', {alt:\"\", src:\"https://wpt.fyi/static/safari_64x64.png\"}));\n    if(name == \"Firefox\") icon.push(el('img', {alt:\"\", src:\"https://wpt.fyi/static/firefox_64x64.png\"}));\n\n    return el('li', {\"class\":passClass},\n        el('nobr', {'class':'browser'}, ...icon, ` ${name} ${shortVersion}`),\n        el('br', {}),\n        el('nobr', {'class':'pass-rate'}, `${passes}/${total}`)\n    );\n}\n</script>"
  },
  {
    "path": "redirects.md",
    "content": "# Enabling Text Fragments in Client-Side Redirects\n\n## Background\n\nLinks with text fragments do not properly work with client-side redirects.  For\nexample, clicking this link:\n\n[https://t.co/9JkH5EOXO1?amp=1](https://t.co/9JkH5EOXO1?amp=1)\n\nresults in a client-side redirect to\nhttps://www.babynames.com/#:~:text=%23blacklivesmatter, which is loaded by the\nbrowser, but #blacklivesmatter is not highlighted as is desired.  However,\nclicking on the link itself results in the intended behavior.\n\nIn Chrome, links with text fragments\n[require a user activation](https://github.com/WICG/scroll-to-text-fragment#user-content-security-considerations:~:text=Additionally%2C%20a%20text%20directive%20is%20invoked,one%20in%20its%20browsing%20context%20group.)\nto scroll to the fragment.  Server-side redirects (using 3xx status codes)\npropagate the original user activation bit, and thus work as intended.  However,\nclient-side redirects (200 response with javascript that modifies\nwindow.location) cannot tie the original user activation to the window.location\nnavigation.\n\nWe expect sharing to be a major use case for text fragment links;\ntoday, users (e.g. on Twitter) share screenshots of highlighted text,\noften without the attributing link ([example](https://twitter.com/dellcam/status/1273255557743497221)).\n\nWe see two, non-mutually-exclusive, solutions: move the ecosystem away from\nclient-side redirects towards server-side redirects and/or implement a\ntext-fragment specific solution.\n\n## Moving the ecosystem towards server side redirects\n\nSeveral sites and apps (most prominently Twitter and their t.co links,\nHangouts, Facebook) use client-side redirects instead of server side redirects.\nWe've done some background research and found some specific reasons for this\npreference:\n\n* Attribution: Server-side redirects attribute clicks to the source website,\n  which makes social platforms look smaller.  In particular, when a user\n  clicks a t.co url on example.com, Twitter would like the referrer to show\n  t.co. This seems like a major blocker and would require additions to HTTP\n  referrer-policy or a new header.\n* Interop and Bugs: A lack of interoperable behavior in how various edge-cases\n  are treated means that client-side redirects (which had more interoperable\n  behavior) were easier to use. Example bugs:\n  * Safari loses fragments in an HTTP redirect - [WebKit 24175](https://bugs.webkit.org/show_bug.cgi?id=24175) (fixed!)\n  * Safari loses fragment in multiple HTTP redirects - [WebKit 158420](https://bugs.webkit.org/show_bug.cgi?id=158420)\n  * Safari rewrites Search URLs (to be friendly) but loses fragments - the URL rewriter is avoided using a client-side redirect: [WebKit 194925](https://bugs.webkit.org/show_bug.cgi?id=194925).\n\n  It seems the situation here has improved significantly over the years, though\n  there's still some way to go and it will take time for the fixes to be\n  deployed at sufficient scale.\n* Privacy and security: Client-side redirects have been used to strip PII\n  (referrer headers). They can also be used to present an interstitial before\n  navigating. We believe these use cases predate support for referrer-policy\n  and could now be satisfied using 3xx redirects (however, with non-trivial\n  effort)\n\nIn theory, these obstacles can be overcome through a combination of evangelism\nand modifications to HTTP referrer policy.  In practice, historical bugs and\ninconsistencies make this a long-term battle.\n\nIt should be noted that server side redirects are generally accepted across the\nindustry as the better practice. Making this shift would also help in allowing\ntransmission of other headers like Sec-Fetch-User. For these reasons, moving\nthe ecosystem towards server-side redirects should be the long-term goal.\nHowever, we'll need a fix for the more immediate future as moving the ecosystem\nwill be, at minimum, a years-long effort.\n\n## Text-Fragment-specific Solution\n\nNote: This was previously called the \"Text Fragment Token\" but renamed, see\n#178.\n\nIntroduce a \"text fragment activation flag\". This flag grants permission to\ninvoke a text fragment. The flag can be used during a document load to invoke\nthe text fragment, or it can be passed into a navigation to grant permission to\nthe next page without requiring a user activation. However, in either case, the\nflag is consumed so a page cannot both invoke a text fragment and pass the flag.\n\nThe flag is set in only one place, during document load, and it is only set if\nthe load is the result of a user initiated navigation. Thus, this mechanism can\nbe thought of as a user activation that applies only to text fragments, whose\nlifetime extends across navigations but can be used only once (is always\nconsumed on use). Effectively, it allows a page to successfully navigate to a\ntext-fragment without a user gesture once; however, further attempts require a\nuser gesture since the flag is consumed and only generated by a user gesture.\n\n### Example\n\n![Diagram showing an example text-fragment activation through a client-side redirect](text_fragment_activation_flag.png)\n\n1. User clicks a link to https://e.co/abcde; a link through a popular\n  redirection service. This creates a user activation in the window which is\n  consumed and stored by the navigation request.\n2. The e.co redirector sends a 200 response with script in the body. Because\n  the navigation request has a user activation bit, the document load consumes\n  it to create a new text fragment activation flag. Note: user activations on\n  navigations are used only to identify the navigation as having been initiated\n  by a user activation - it does not confer a user activation on the destination\n  browsing context.\n3. The script now navigates the frame to the real destination:\n  https://a.com#:~:text=foo. It consumes its text fragment activation flag and sets it on\n  the navigation request. At this point, even if the page were to continue\n  loading, it would not be allowed to activate a text fragment since the flag\n  has been consumed.\n4. The response from a.com is received. Its request does not have a user\n  activation associated with it, but it does have a text fragment activation\n  flag. The request's flag is consumed and transfered to the newly loading\n  document.\n5. Because the document has a text fragment activation flag, it is consumed to\n  activate the text fragment in the URL and scroll it into view.\n\n## FAQ\n\n#### Why is it ok to allow a user activation for a text-fragment to cross a navigation boundary?\n\nSuppose an attacker convinces a user to click a link to `evil.com`. `evil.com`\ncan (at an arbitrary time) navigate with `window.location =\n\"secure.com#:~:text=...\"` and the text fragment will activate (assuming other,\nnon-user-activation, conditions are met). i.e. If the user navigated to an\nattacker's page with a user activation, the attacker's page can cause 1\ntext-fragment navigation to a destination of their choice.\n\nWhy is this ok?\n\n* evil.com has to navigate itself away, it would need an additional user\n  activation to open a popup. Text fragments wont activate if there's multiple\n  entries in the browsing context group so it shouldn't be able to see what\n  happens on the destination page anyway.\n* If the attacker can convince to user to click a link to evil.com, they could\n  have sent them straight to the destination page as well. It's possible they\n  might use their own page to setup some state, but text fragment activation\n  still requires [an isolated browsing context\n  group](https://wicg.github.io/scroll-to-text-fragment/#ref-for-session-history:~:text=If%20document%E2%80%99s%20browsing%20context%20is%20a,set%20has%20length%201%20return%20true).\n* The main benefit a user activation provides is that if an attacker does find\n  some side channel that lets them see the text fragment effect on the\n  destination, they cannot repeat the attack arbitrarily. This still holds.\n\nIn short, the user activation is mainly meant to prevent a repeatable attack since\nextracting a single activation from a user isn't a high bar. The other\n[mitigations described in the spec](https://wicg.github.io/scroll-to-text-fragment/#security-and-privacy)\nremain sufficient.\n\n#### Why not just propagate user activations?\n\nThis seems much scarier since lots of other things rely on user activations and\ndon't share the above properties so this would have much wider implications.\nAlso, because of the other uses, consuming the user activation from text fragments\nisn’t straightforward. Here, we can consume the text fragment when forwarded or\nactivated; this ensures that 1 user activation allows only 1 text fragment\nactivation.\n\n#### Will this work through multiple redirects?\n\nYes - the flag is only consumed when a URL with a text fragment is loaded so\nintermediate pages will propagate it. For example, a link in Hangouts Chat\nactually does two redirects.\n\n#### Does this mean a flag could be propagated indefinitely?\n\nYes - but this should be ok because its only purpose is to activate a text\nfragment and it cannot be cloned; we still maintain 1 user activation == 1\nactivation. We could add some limit or consume on pages without a text fragment\nafter some timeout but this seems like it would add complexity, introduce\nbrittleness, and have limited benefit.\n"
  },
  {
    "path": "security-privacy-questionnaire.md",
    "content": "#### 2.1. What information might this feature expose to Web sites or other parties, and for what purposes is that exposure necessary?\n\nThe targetText value that will be added to the URL fragment contains a portion of text that is expected to be in the page. This information is either already on the page, or isn't on the page but was expected to be, so shouldn't be a privacy concern.\n\n#### 2.2. Is this specification exposing the minimum amount of information necessary to power the feature?\n\nThe feature itself does not expose information. The URL creator (e.g. a website providing a reference or a user sharing a targetText URL) adds some amount of information to the URL using this feature, but this is information expected to be in the target page. We have restrictions in place to prevent exfiltration of page contents using this feature:\n- Restricted to top-level frames (no iframes)\n- Restricted to non-same-page activations\n- Restricted to pages without an opener (no window.open)\n\n#### 2.3. How does this specification deal with personal information or personally-identifiable information or information derived thereof?\n\nIt doesn't - The user could theoretically place PII in the targetText, exposing it to the page, but this would imply they expect the information to appear on the page and want to link to it.\n\n#### 2.4. How does this specification deal with sensitive information?\n\nIt doesn't - See previous question.\n\n#### 2.5. Does this specification introduce new state for an origin that persists across browsing sessions?\n\nNo.\n\n#### 2.6. What information from the underlying platform, e.g. configuration data, is exposed by this specification to an origin?\n\nNone.\n\n#### 2.7. Does this specification allow an origin access to sensors on a user’s device\n\nNo.\n\n#### 2.8. What data does this specification expose to an origin? Please also document what data is identical to data exposed by other features, in the same or different contexts.\n\nJust the targetText value as addressed in question 1.\n\n#### 2.9. Does this specification enable new script execution/loading mechanisms?\n\nNo.\n\n#### 2.10. Does this specification allow an origin to access other devices?\n\nNo.\n\n#### 2.11. Does this specification allow an origin some measure of control over a user agent’s native UI?\n\nSimilar to an element fragment anchored URL, the origin can cause the UA to change scroll position on navigation. We propose restricting the feature to non-same-doc full navigations, so an origin can't use this to manipulate the scroll position on the current page.\n\n#### 2.12. What temporary identifiers might this this specification create or expose to the web?\n\nNone.\n\n#### 2.13. How does this specification distinguish between behavior in first-party and third-party contexts?\n\nThird-party contexts cannot access the URL fragment, so there should be no way to access the targetText. The most a cross-origin iframe can check is document.referrer, but document.referrer does not include the URL fragment.\n\n#### 2.14. How does this specification work in the context of a user agent’s Private \\ Browsing or \"incognito\" mode?\n\nThe feature works the same in a private browsing context, and does not reveal private browsing mode or provide information to correlate private browsing activity.\n\n#### 2.15. Does this specification have a \"Security Considerations\" and \"Privacy Considerations\" section?\n\nYes.\n\n#### 2.16. Does this specification allow downgrading default security characteristics?\n\nNo.\n"
  },
  {
    "path": "w3c.json",
    "content": "{\n    \"group\":      [80485],\n    \"contacts\":   [\"yoavweiss\"],\n    \"repo-type\":  \"cg-report\"\n}\n"
  }
]