{"id":16592189,"url":"https://github.com/pveyes/text-fragments","last_synced_at":"2025-08-19T08:39:14.928Z","repository":{"id":77329204,"uuid":"377133738","full_name":"pveyes/text-fragments","owner":"pveyes","description":"Text Fragments and Selection utilities","archived":false,"fork":false,"pushed_at":"2022-04-20T08:38:23.000Z","size":142,"stargazers_count":9,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-09T07:11:12.509Z","etag":null,"topics":["dom","dom-selection","fragments","oss","selection","text","text-fragment-url","text-fragments"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pveyes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-06-15T11:08:45.000Z","updated_at":"2024-10-23T15:06:25.000Z","dependencies_parsed_at":null,"dependency_job_id":"23f9f39c-c297-4764-bbd6-01e4246c464e","html_url":"https://github.com/pveyes/text-fragments","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/pveyes/text-fragments","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pveyes%2Ftext-fragments","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pveyes%2Ftext-fragments/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pveyes%2Ftext-fragments/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pveyes%2Ftext-fragments/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pveyes","download_url":"https://codeload.github.com/pveyes/text-fragments/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pveyes%2Ftext-fragments/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271123416,"owners_count":24703225,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-19T02:00:09.176Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dom","dom-selection","fragments","oss","selection","text","text-fragment-url","text-fragments"],"created_at":"2024-10-11T23:19:54.293Z","updated_at":"2025-08-19T08:39:14.920Z","avatar_url":"https://github.com/pveyes.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# text-fragments\n\n\u003e [Text Fragments](https://web.dev/text-fragments) and [Selection](https://developer.mozilla.org/en-US/docs/Web/API/Selection) utilities.\n\n## Features\n\n- Normalized Selection\n- Create excerpt from selected text\n- Efficient Text Fragments generation\n- Lightweight (~1kB minified gzipped)\n- Optional React Bindings\n\n## APIs\n\n### Selection\n\nThis is not intended to be a one-stop shop for `Selection` and `Range`, but rather few useful function related to Text Fragments generation. For selection-related utilities, it will use `LiteSelection` with type as follows\n\n```ts\ninterface LiteSelection {\n  anchorNode: Node | null;\n  anchorOffset: number;\n  focusNode: Node | null;\n  focusOffset: number;\n}\n```\n\n#### `getSelection(): LiteSelection | null`\n\nThis function return a normalized `Selection` in the form of `LiteSelection`, or `null` if it's a collapsed selection or not a range selection.\n\n```ts\nimport { getSelection } from 'text-fragments';\n\nconst selection = getSelection();\n\nif (selection) {\n  // do something with the selection\n}\n```\n\nBecause this is normalized, you can be sure that `anchorNode` is always point to the element before `focusNode`, and in case where it points to the same node, `anchorOffset` will always be less than `focusOffset`.\n\n#### `getSelectedText(selection: LiteSelection, options?: SelectedTextOptions): string`\n\nReturn the text inside a selection. It accepts an optional `options` that you can use to pass `maxLength` or `moreTextIndicator`. This can be useful to create an excerpt or limit the\n\n```ts\nimport { getSelection, getSelectedText } from 'text-fragments';\n\nconst selection = getSelection();\nconst text = getSelection(selection, {\n  maxLength: 100, // defaults to infinity / ignored\n  moreTextIndicator: '', // defaults to ...\n});\n```\n\n### Text Fragments\n\nThere are 2 main function to generate Text Fragments, one with hash \u0026 one without. The algorithm used to generate Text Fragments is optimized for smallest string possible with the high chance of correctly highlighting a text. It might highlight the wrong portion of the text but the chances are pretty slim.\n\n#### `getTextFragmentsWithHash(selection: LiteSelection): string`\n\nReturn text fragments string in the form of location hash. You can immediately use this by appending to current URL\n\n```ts\nimport { getSelection, getTextFragmentsWithHash } from 'text-fragments';\n\nconst selection = getSelection();\nconst hash = getTextFragmentsWithHash(selection);\nconst url = window.location.href + hash;\n// do something with the url\n```\n\n#### `getTextFragments(selection: LiteSelection): string`\n\nSame as before, but without the `#:~:text=` [prefix](https://web.dev/text-fragments/#textstart).\n\n```ts\nimport { getSelection, getTextFragmentsWithHash } from 'text-fragments';\n\nconst selection = getSelection();\nconst textFragments = getTextFragments(selection);\n```\n\n### Optional React bindings\n\nThere's also an optional React binding in the form of hooks that you can import via `text-fragments/react`\n\n#### `useSelection(): LiteSelection | null`\n\nThe value returned by `useSelection` automatically reflects current selection and updates whenever user changes their selection in the document.\n\n```tsx\nimport { getSelectedText } from 'text-fragments';\nimport { useSelection } from 'text-fragments/react';\n\nconst selection = useSelection();\n\nreturn (\n  \u003cdiv\u003e\n    {selection \u0026\u0026 \u003cp\u003eCurrently selecting {getSelectedText(selection)}\u003c/p\u003e}\n  \u003c/div\u003e\n);\n```\n\n#### `useTextFragments(options?: { includeHash: boolean }): string | null`\n\nGet Text Fragments based on current selection. Similar to `useSelection` this value is automatically updated.\n\n```tsx\nimport { useTextFragments } from 'text-fragments/react';\n\nconst hash = useTextFragments({ includeHash: true });\n\nfunction handleShare() {\n  window.open(window.location.href + hash);\n}\n\nreturn (\n  \u003cdiv\u003e\n    \u003cbutton onClick={handleShare}\u003ePreview\u003c/button\u003e\n    \u003cParagraph /\u003e\n  \u003c/div\u003e\n);\n```\n\n## Related Projects\n\nIf you want a more robust library you can use `fragment-generation-utils` from [`text-fragments-polyfill`](https://github.com/GoogleChromeLabs/text-fragments-polyfill). It weighs in about 7kB minified gzipped.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpveyes%2Ftext-fragments","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpveyes%2Ftext-fragments","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpveyes%2Ftext-fragments/lists"}