{"id":15684459,"url":"https://github.com/neurosnap/scopeify-html","last_synced_at":"2025-05-07T16:05:08.496Z","repository":{"id":138553470,"uuid":"67810915","full_name":"neurosnap/scopeify-html","owner":"neurosnap","description":"Scope all CSS selectors in HTML","archived":false,"fork":false,"pushed_at":"2017-08-01T15:36:37.000Z","size":119,"stargazers_count":10,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-21T03:59:59.589Z","etag":null,"topics":["email","html","scope","scoped-selectors"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/neurosnap.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"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":"2016-09-09T15:35:13.000Z","updated_at":"2022-02-28T12:40:50.000Z","dependencies_parsed_at":"2023-06-10T15:45:22.166Z","dependency_job_id":null,"html_url":"https://github.com/neurosnap/scopeify-html","commit_stats":{"total_commits":24,"total_committers":1,"mean_commits":24.0,"dds":0.0,"last_synced_commit":"61dffbdec4fd01548efcde32bb6907ec65f2eafe"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neurosnap%2Fscopeify-html","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neurosnap%2Fscopeify-html/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neurosnap%2Fscopeify-html/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neurosnap%2Fscopeify-html/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/neurosnap","download_url":"https://codeload.github.com/neurosnap/scopeify-html/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252590572,"owners_count":21772936,"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","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":["email","html","scope","scoped-selectors"],"created_at":"2024-10-03T17:17:10.276Z","updated_at":"2025-05-07T16:05:08.488Z","avatar_url":"https://github.com/neurosnap.png","language":"JavaScript","readme":"Scopeify HTML [![Build Status](https://travis-ci.org/neurosnap/scopeify-html.svg?branch=master)](https://travis-ci.org/neurosnap/scopeify-html)\n=============\n\nThe goal of this library is to scope all CSS selectors in an HTML document.\n\nFeatures\n--------\n\n* Every CSS selector is scoped\n* Media queries are scoped and preserved\n* Fonts are scoped and preserved\n* Keyframes are scoped and preserved\n* Can use PostCSS plugins to modify all extracted CSS\n* Ability to do aditional processing with PostCSS\n\nWhy\n---\n\nThe primary reason for creating this library was to render HTML and CSS inside\na document without that CSS effecting the parent document.  Basically this library\nwas created to avoid having to use an iframe.\n\nOther libraries that attempt to solve this problem, such as [juice](https://github.com/Automattic/juice)\ndo so by inlining all the CSS, which loses pseudo selectors, keyframes, and font-face names.\n\nHow it works\n------------\n\nThe core functionality of this library comes from [PostCSS](https://github.com/postcss/postcss).\nWe are using [postcss-scopeify-everything](https://github.com/neurosnap/postcss-scopeify-everything)\nto perform all the selector scope transformations.\n\nWe iterate over all the CSS rules within an HTML document and scope all of them using a hash of the content.  Then we iterate\nover all the DOM elements in the document and apply the newly scoped selectors.  Then we return the\ndocument and the CSS separated.\n\n* Scope CSS by converting the following selectors and names in the HTML document:\n  * Convert HTML elements into scoped classes,\n  * Ids,\n  * Classes,\n  * Keyframe names, and\n  * Font-face names\n* Convert all HTML selectors into scoped selectors\n\nUsage\n-----\n\n```js\nconst scopeifyHtml = require('scopeify-html');\nconst insertCss = scopeifyHtml.insertCss;\nconst getCss = scopeifyHtml.getCss;\n\nconst html = `\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n\u003chead\u003e\n  \u003cstyle\u003e\n    .foo { display: flex; }\n    div { margin: 10px; border: 1px solid black; }\n    #bar { flex: 1; font-size: 18px; }\n  \u003c/style\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n  \u003cdiv class=\"foo\"\u003e\n    \u003cdiv\u003eAll your base\u003c/div\u003e\n    \u003cdiv id=\"bar\"\u003eAre belong to us\u003c/div\u003e\n  \u003c/div\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n`;\n\nconst parser = new DOMParser();\nconst doc = parser.parseFromString(html, \"text/html\");\n\nconst scoped = scopeifyHtml().sync(doc);\nconsole.log(scoped);\n/*\n{\n  elements: { div: 'div_el_3BuKMO' },\n  classes: { foo: 'foo_3BuKMO' },\n  ids: { bar: 'bar_3BuKMO' },\n  keyframes: {},\n  fontFaces: {}\n}\n*/\n\nconst scopedCss = getCss(scoped);\nconsole.log(scopedCss);\n/*\n  .foo_3BuKMO { display: flex; }\n  .div_el_3BuKMO { margin: 10px; border: 1px solid black; }\n  #bar_3BuKMO { flex: 1; font-size: 18px; }\n*/\n\n// insert scoped CSS into DOM \u003chead\u003e\ninsertCss(scopedCss, doc);\n\nconsole.log(doc.documentElement.outerHTML);\n/*\n\u003chtml\u003e\n\u003chead\u003e\n  \u003cstyle type=\"text/css\"\u003e\n    .foo_3BuKMO { display: flex; }\n    .div_el_3BuKMO { margin: 10px; border: 1px solid black; }\n    #bar_3BuKMO { flex: 1; font-size: 18px; }\n  \u003c/style\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n  \u003cdiv class=\"foo_3BuKMO div_el_3BuKMO\"\u003e\n    \u003cdiv class=\"div_el_3BuKMO\"\u003eAll your base\u003c/div\u003e\n    \u003cdiv id=\"bar_3BuKMO\" class=\"div_el_3BuKMO\"\u003eAre belong to us\u003c/div\u003e\n  \u003c/div\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n*/\n```\n\n### Async promise\n\n```js\nconst scopeifyHtml = require('scopeify-html');\nconst insertCss = scopeifyHtml.insertCss;\nconst getCss = scopeifyHtml.getCss;\n\nconst html = '\u003cdiv\u003ehi mom\u003c/div\u003e';\nconst parser = new DOMParser();\nconst doc = parser.parseFromString(html, \"text/html\");\n\nscopeifyHtml({ replaceClassName: true })\n  .promise(doc)\n  .then((scoped) =\u003e {\n    const scopedCss = getCss(scoped);\n    insertCss(scopedCss, doc);\n  })\n  .catch(console.log);\n```\n\nAPI\n---\n\n### scopeifyHtml\n\nPrimary entry point for the library.\n\n#### scopeifyHtml(options: Object)\n\n* replaceClassName (Boolean, default `false`): Removes any classnames not used in CSS\n\nThe options passed here will also be passed to [postcss-scopeify-everything](https://github.com/neurosnap/postcss-scopeify-everything#options)\n* plugins (Array, default `[]`): adds PostCSS plugins before the scopeify plugin\n* scopeifyFn (Function): the function that hashes the identifier name\n* scopeifyElFn (Function): the function that converts an element name to a class name\n* asteriskName (Function|String, default `__asterisk`): the string that is used for the wildcard selector `*`\n* ids (Boolean, default `false`): determines whether or not to disable scoping `ids`\n* elements (Boolean, default `false`): determines whether or not to disable scoping `elements`\n* classes (Boolean, default `false`): determines whether or not to disable scoping `classes`\n* keyframes (Boolean, default `false`): determines whether or not to disable scoping `keyframes`\n* fontFaces (Boolean, default `false`): determines whether or not to disable scoping `fontFaces`\n\n### sync\n\nSynchronously processes the CSS and HTML\n\n`scopeifyHtml().sync(doc: Document) =\u003e scopedSelectors`\n\n### promise\n\nAsynchronously processes the CSS and HTML\n\n`scopeifyHtml().promise(doc: Document) =\u003e Promise(scopedSelectors)`\n\n### getCss\n\nReturns the CSS from scopeify\n\n`scopeifyHtml.getCss(scopedSelectors) =\u003e string`\n\n### insertCss\n\nInserts CSS into document\n\n`scopeify.insertCss(css: string, doc: Document) =\u003e undefined`\n\nPerf\n----\n\nAll speeds are measured in milliseconds (ms).\n\nfixture        | scopeify-html | juice v4   |\n---------------|---------------|------------|\nzillow.html    | 43.316        | 81.557     |\ngog.html       | 126.074       | 55.336     |\nreadme_ex.html | 1.301         | 1.240      |\napple.html     | 114.198       | 26.452     |\ncostco.html    | 1.623         | 0.654      |\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneurosnap%2Fscopeify-html","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fneurosnap%2Fscopeify-html","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneurosnap%2Fscopeify-html/lists"}