{"id":20578617,"url":"https://github.com/schalkventer/react-html-connector","last_synced_at":"2026-04-12T06:31:53.668Z","repository":{"id":89442047,"uuid":"139138390","full_name":"schalkventer/react-html-connector","owner":"schalkventer","description":"🔌 A JavaScript function that eases integration of React (or Preact) components into existing server-side templating.","archived":false,"fork":false,"pushed_at":"2018-11-09T11:30:26.000Z","size":159,"stargazers_count":2,"open_issues_count":7,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-10-07T19:47:47.767Z","etag":null,"topics":["django","jekyll","php","python","reactjs","ruby","wordpress"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/react-html-connector","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/schalkventer.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2018-06-29T10:51:51.000Z","updated_at":"2018-11-09T11:30:27.000Z","dependencies_parsed_at":null,"dependency_job_id":"3a6319f7-0973-46b6-8f26-fdb1e25b552d","html_url":"https://github.com/schalkventer/react-html-connector","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/schalkventer/react-html-connector","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schalkventer%2Freact-html-connector","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schalkventer%2Freact-html-connector/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schalkventer%2Freact-html-connector/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schalkventer%2Freact-html-connector/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/schalkventer","download_url":"https://codeload.github.com/schalkventer/react-html-connector/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schalkventer%2Freact-html-connector/sbom","scorecard":{"id":803716,"data":{"date":"2025-08-11","repo":{"name":"github.com/schalkventer/react-html-connector","commit":"a73ce2e28b50419a83b8abcbf079f2b800f89cec"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.3,"checks":[{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":0,"reason":"93 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-6chw-6frg-f759","Warn: Project is vulnerable to: GHSA-v88g-cgmw-v5xw","Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw","Warn: Project is vulnerable to: GHSA-fwr7-v2mv-hh25","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-cwfw-4gq5-mrqx","Warn: Project is vulnerable to: GHSA-g95f-p29q-9xw4","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-x9w5-v3q2-3rhw","Warn: Project is vulnerable to: GHSA-w8qv-6jwh-64r5","Warn: Project is vulnerable to: GHSA-c6rq-rjc2-86v2","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-w573-4hg7-7wgq","Warn: Project is vulnerable to: GHSA-vh7m-p724-62c2","Warn: Project is vulnerable to: GHSA-r9p9-mrjm-926w","Warn: Project is vulnerable to: GHSA-434g-2637-qmqr","Warn: Project is vulnerable to: GHSA-49q7-c7j4-3p7m","Warn: Project is vulnerable to: GHSA-977x-g7h5-7qgw","Warn: Project is vulnerable to: GHSA-f7q4-pwc6-w24p","Warn: Project is vulnerable to: GHSA-fc9h-whq2-v747","Warn: Project is vulnerable to: GHSA-vjh7-7g9h-fjfh","Warn: Project is vulnerable to: GHSA-qrmc-fj45-qfc2","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-8r6j-v8pm-fqw3","Warn: Project is vulnerable to: MAL-2023-462","Warn: Project is vulnerable to: GHSA-vvj3-85vf-fgmw","Warn: Project is vulnerable to: GHSA-q42p-pg8m-cqh6","Warn: Project is vulnerable to: GHSA-w457-6q6x-cgp9","Warn: Project is vulnerable to: GHSA-62gr-4qp9-h98f","Warn: Project is vulnerable to: GHSA-f52g-6jhx-586p","Warn: Project is vulnerable to: GHSA-2cf5-4w76-r9qv","Warn: Project is vulnerable to: GHSA-3cqr-58rm-57f8","Warn: Project is vulnerable to: GHSA-g9r4-xpmj-mj65","Warn: Project is vulnerable to: GHSA-q2c6-c6pm-g3gh","Warn: Project is vulnerable to: GHSA-765h-qjxv-5f44","Warn: Project is vulnerable to: GHSA-f2jv-r9rf-7988","Warn: Project is vulnerable to: GHSA-43f8-2h32-f4cj","Warn: Project is vulnerable to: GHSA-qqgx-2p2h-9c37","Warn: Project is vulnerable to: GHSA-2pr6-76vf-7546","Warn: Project is vulnerable to: GHSA-8j8c-7jfh-h6hx","Warn: Project is vulnerable to: GHSA-896r-f27r-55mw","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-6c8f-qphg-qjgp","Warn: Project is vulnerable to: GHSA-76p3-8jx3-jpfq","Warn: Project is vulnerable to: GHSA-3rfm-jhwj-7488","Warn: Project is vulnerable to: GHSA-hhq3-ff78-jv3g","Warn: Project is vulnerable to: GHSA-4xc9-xhrj-v574","Warn: Project is vulnerable to: GHSA-x5rq-j2xg-h7qm","Warn: Project is vulnerable to: GHSA-jf85-cpcp-j695","Warn: Project is vulnerable to: GHSA-p6mc-m468-83gw","Warn: Project is vulnerable to: GHSA-29mw-wpgm-hmr9","Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm","Warn: Project is vulnerable to: GHSA-4xcv-9jjx-gfj3","Warn: Project is vulnerable to: GHSA-f9cm-qmx5-m98h","Warn: Project is vulnerable to: GHSA-7wpw-2hjm-89gp","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-vh95-rmgr-6w4m","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-fhjf-83wg-r2j9","Warn: Project is vulnerable to: GHSA-r683-j2x4-v87g","Warn: Project is vulnerable to: GHSA-5fw9-fq32-wv5p","Warn: Project is vulnerable to: GHSA-hj48-42vr-x3v9","Warn: Project is vulnerable to: GHSA-h7cp-r72f-jxh6","Warn: Project is vulnerable to: GHSA-v62p-rq8g-8h59","Warn: Project is vulnerable to: GHSA-hrpp-h998-j3pp","Warn: Project is vulnerable to: GHSA-mvjj-gqq2-p4hw","Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-h9rv-jmmf-4pgx","Warn: Project is vulnerable to: GHSA-hxcc-f52p-wc94","Warn: Project is vulnerable to: GHSA-4g88-fppr-53pp","Warn: Project is vulnerable to: GHSA-4jqc-8m5r-9rpr","Warn: Project is vulnerable to: GHSA-vx3p-948g-6vhq","Warn: Project is vulnerable to: GHSA-j44m-qm6p-hp7m","Warn: Project is vulnerable to: GHSA-3jfq-g458-7qm9","Warn: Project is vulnerable to: GHSA-r628-mhmh-qjhw","Warn: Project is vulnerable to: GHSA-9r2w-394v-53qc","Warn: Project is vulnerable to: GHSA-5955-9wpr-37jh","Warn: Project is vulnerable to: GHSA-qq89-hq3f-393p","Warn: Project is vulnerable to: GHSA-f5x3-32g6-xq36","Warn: Project is vulnerable to: GHSA-52f5-9888-hmc6","Warn: Project is vulnerable to: GHSA-jgrx-mgxx-jf9v","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3","Warn: Project is vulnerable to: GHSA-662x-fhqg-9p8v","Warn: Project is vulnerable to: GHSA-394c-5j6w-4xmx","Warn: Project is vulnerable to: GHSA-78cj-fxph-m83p","Warn: Project is vulnerable to: GHSA-fhg7-m89q-25r3","Warn: Project is vulnerable to: GHSA-6fc8-4gx4-v693","Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q","Warn: Project is vulnerable to: GHSA-c4w7-xm78-47vh","Warn: Project is vulnerable to: GHSA-p9pc-299p-vxgp"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-23T11:13:31.896Z","repository_id":89442047,"created_at":"2025-08-23T11:13:31.896Z","updated_at":"2025-08-23T11:13:31.896Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31706764,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-12T06:22:27.080Z","status":"ssl_error","status_checked_at":"2026-04-12T06:21:52.710Z","response_time":58,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["django","jekyll","php","python","reactjs","ruby","wordpress"],"created_at":"2024-11-16T06:13:56.982Z","updated_at":"2026-04-12T06:31:53.659Z","avatar_url":"https://github.com/schalkventer.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🔌 React HTML Connector \u0026middot; [![](https://travis-ci.org/schalkventer/react-html-connector.svg?branch=master)](https://travis-ci.org/schalkventer/react-html-connect) [![](https://img.shields.io/npm/dm/react-html-connector.svg)](https://www.npmjs.com/package/react-html-connector) [![](https://img.shields.io/badge/stability-experimental-orange.svg)](#package-state)\n\nA JavaScript function that eases integration  of [React](https://reactjs.org/) (or [Preact](https://preactjs.com/)) components into existing server-side templating.\n\nWorks with:\n- [Wordpress](https://wordpress.org)\n- [Magento](https://www.magento.com/)\n- [Jekyll](https://jekyllrb.com/)\n- [Django](https://www.djangoproject.com/)\n\n## Development\n\nThis package is still considered experimental. This means that it works as intended, however features may still change or get removed in future versions. It is currently used in-house by the team at [OpenUp](https://github.com/orgs/OpenUpSA), however feel free to try it out and provide feedback via Github issues. If it addresses a use-case that is important to you please let me know at [schalk@openup.org.za](mailto:schalk@openup.org.za).\n\n## Usage\n\nThis package is intended to be imported into a NodeJS module resolver like [Webpack](https://webpack.js.org/). \n\nHowever it is built in accordance with the [UMD JavaScript specification](https://github.com/umdjs/umd). This means that it can also be pulled directly into the browser via a `\u003cscript\u003e` tag from the following URL:\n\n```\n\u003cscript src=\"http://unpkg.com/react-html-connector\"\u003e\u003c/script\u003e\n```\n\n## Getting Started\n\n##### 1. Make sure that you have the latest version of [NodeJS](https://nodejs.org/en/) installed:\n\n##### 2. Install the package alongside _React_ and _React DOM_:\n```\nnpm install --save react react-dom react-html-connector\n```\n\n##### 3. Create your server-side template:\n```\n// Users.php\n\n\n\u003cbody\u003e\n  \u003cdiv data-component=\"Users\"\u003e\n    \u003ch1 data-title\u003eUsers List\u003c/h1\u003e\n    \u003cul\u003e\n      \u003c?php foreach ($user_array as $user): ?\u003e\n        \u003cli data-users \u003c?php $user[active] ? echo \"data-active\" : null ?\u003e\n          \u003cspan data-name\u003e\u003c?php $user[name] ?\u003e\u003c/span\u003e\n        \u003c/li\u003e\n      \u003c?php endforeach ?\u003e\n    \u003c/ul\u003e\n  \u003c/div\u003e\n\u003c/body\u003e\n\n\n\u003cscript src=\"scripts.min.js\"\u003e\u003c/script\u003e\n```\n##### 4. Create your React component\n\n```\n// Users.jsx\n\n\nclass Users extends React.Component {\n  constructor(props) {\n    super(props);\n    this.state = {\n      showAll: true,\n    }\n    \n    this.toggleShowAll = this.toggleShowAll.bind(this);\n  }\n\n  toggleShowAll() {\n    this.setState({ showAll: !this.state.showAll })\n  }\n\n  render() {\n    return (\n      \u003cdiv\u003e\n        \u003ch1\u003e{this.props.title}\u003c/h1\u003e\n        \u003cul\u003e\n          {\n            this.props.users.map((user) =\u003e {\n              if (!this.state.showAll \u0026\u0026 !user.active) {\n                return null;\n              }\n\n              return (\n                \u003cli key={user.id}\u003e\n                  \u003cspan\u003e{user.name}\u003c/span\u003e\n                \u003c/li\u003e\n              )\n            })\n          }\n        \u003c/ul\u003e\n        \u003cbutton onClick={this.toggleShowAll}\u003e\n          {this.state.showAll ? 'Hide inactive' : 'Show inactive'}\n        \u003c/button\u003e\n      \u003c/div\u003e\n    )\n  }\n}\n```\n\n\n##### 4. Connect React component to your 'data-component' attribute:\n\n```\n// scripts.jsx\n\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport ReactHtmlConnector from 'react-html-connector';\n\n\n// Create an instance of React HTML Connector.\nconst userConnector = new ReactHtmlConnector(React.createElement, ReactDOM.render);\n\n\n// Define how values from template should be passed as props.\nconst query = {\n  title: 'innerHTML',\n  users: [\n    {\n      id: 'number',\n      active: 'boolean',\n      name: 'innerHTML',\n    }\n  ]\n}\n\n\n// Call `connect` to bind the 'User' component and associated properties to your template.\nuserConnector.connect(Users, 'Users', query)\n```\n\n##### 5. Congrats! Your component should be bound to the `data-component=\"Users\"` attribute.\nView a live Codepen example of the above at [https://codepen.io/schalkventer/pen/oyJeqg](https://codepen.io/schalkventer/pen/oyJeqg).\n\n## API\n\n### ReactHtmlConnector\n\nThe `react-html-connector` package exposes a JavaScript class. The constructor associated with this class returns an object with various methods that can be called to ease integration of React with server-side templating.\n\n```\nconst connectorInstance = new ReactHtmlConnector(createElement, render, options)\n```\n\n##### `createElement \u003cfunction\u003e` _required_\nNeeds to be a React (or a React-like) `createElement` method (for example: `React.createElement`). By passing this manually you are able to pass a specific version of React or React-like library. In order to use this package with Preact you need to pass [Hyperscript](https://github.com/hyperhype/hyperscript) instead of the React `createElement` method (for example: `Preact.h`).\n\n##### `render \u003cfunction\u003e` _required_\nNeeds to be a React (or React-like) `render` method (for example: `ReactDOM.render`). By passing this manually you are able to pass a specific version of React DOM or React-like library. In order to use this package with Preact you need to pass the Preact render method instead of the React DOM `render` method (for example: `Preact.render`).\n\n##### `options \u003cObject\u003e` _optional | default: null_\nAccepts an object of key-value pairs that set specific change the way the returned methods work. See the upcoming parameters for a list of valid `options` values.\n\n##### `options.scope \u003cHTMLelement\u003e `_optional | default: window.document.body_\nRestricts the returned connect and nodeQuery methods' searchable range to a specifc HTML node and its children. Useful for avoid conflicting attribute names used elsewhere in your templates.\n\n##### `options.attribute \u003cstring\u003e `_optional | default: 'data-component'_\nChanges the name of the attribute used to bind components to your templates. Useful when `data-component` is already in use or you want to use a more specific attribute like `data-react-compoment`.\n\n##### `options.library \u003c'react' | 'preact'\u003e` _optional | default: 'react'_ \nChanges how the returned connect method parses params. For example, in Preact you need to pass a fourth parameter into `preact.render` to ensure that a component replaces the targeted HTML node, and not simply appends it to the existing content.\n\n##### `options.store \u003cObject\u003e` _optional | default: null_ \nDescription pending...\n\n##### `options.provider \u003cfunction\u003e` _optional | default: null_ \nDescription pending...\n\n### Methods returned from ReactHtmlConnector constructor:\n\n```\nconst connectorInstance = new ReactHtmlConnector(createElement, render, options);\nconnectorInstance.connect(_component_, _query_);\nconst customQuery = connectorInstance.nodeQuery(_query_);\n```\n\n##### `connectorInstance.connect.component \u003cReact Component\u003e` _required_\nThe React (or React-like) component that will be bound to a specific `data-component` attribute in your template.\n\n##### `connectorInstance.connect.name \u003cstring\u003e` _required_\nThe string value used in the `data-component` attribute of the HTML node you want to target. You can have multiple of the same `data-component` string in a template to initialise multiple instances of a component. Note that the node itself (and everything inside) will be swapped out for the React component.\n\n##### `connectorInstance.connect.query \u003cObject | function\u003e` _optional | default: {}_\nObject literal that instructs what (and how) values should be parsed from your template into props and passed to the component. The object passed to this parameter uses a custom schema, loosely inspired by [GraphQl](https://graphql.org/). This schema will be documented in more detail at some point (See [Issue #2](https://github.com/schalkventer/react-html-connector/issues/2).\n\nAlternatively, a callback function can be passed to this parameter to override the default querying behaviour above. This callback automatically passes the HTML node itself as its first argument. It also passes the `nodeQuery` method (covered below) as it's second argument. The callback should return an object that will then be passed as [props](https://reactjs.org/docs/components-and-props.html) to the React component.\n\n#### `connectorInstance.nodeQuery.query \u003cObject | function\u003e` _optional | default: {}_\nSimilar to `instance.connect.query`, however this method allows you to use the custom querying method independantly of the `instance.connect` method. Useful if you want parse values in your template independantly or before the component is rendered.\n\n\n\n\u003c!-- ## API\n\n\n\n### Primary\n\nconnect(_render_, _component_, _props_, _additional options_)\n- `createElement \u003cfunction\u003e`: This needs to be the React (or React-like) `createElement` method (for example: `React.createElement`). By passing this manually you can control what version of React you want to use, and enables compatibility with React-like libraries such as Preact (for example `Preact.h`). \n- `render \u003cfunction\u003e`: This needs to be a React (or React-like) `render` method (for example: `ReactDOM.render`. By passing this manually you can control what version of React you want to use, and enables compatibility with React-like libraries such as Preact (for example `Preact.h`). \n- `component \u003cReact Component\u003e`: \n- `query \u003cObject\u003e | \u003cfunction\u003e (optional, default: null)`: Optional parameter that instructs the connect function on how to collect and pass values from templates into the component vai props. The value passed to `query` uses custom schema, created specifically for this package (learn more at [Passing props to components](#passing-props-to-components)). Alternatively, `query` also accepts a function for more control over props passed.\n- `options \u003cObject\u003e: (optional, default: null)`: Optional parameter that accepts an object of key/value pairs that sets specific rules/conditions. See the next section for all valid values that can be passed inside `options`:\n\n### Additional Options\n\n- `scope \u003cHTMLelement\u003e (optional, default: window.document)`: A property that restricts the connect function's searchable range to a specifc DOM node and its children. Useful to avoid conflicting attribute names used elsewhere in the template.\n- `attribute \u003cstring\u003e (optional, default: 'data-component')`: A property that changes the name of the attribute used to bind components to your template. Useful when `data-component` is already in use elsewhere.\n- `library \u003c'react' | 'preact'\u003e (optional, default 'react')`: Specifies what library's logic should be used to parse the connect function's params. Currently only supports React and Preact.\n\n## Examples\n\nBelow area a couple of examples to illustrate the connect function can be used:\n\n**Basic Examples**\n- [Basic usage](#basic-usage)\n- [Passing props to components](#passing-props-to-components)\n- [Initialising multiple components](#initialising-multiple-components)\n- [Overriding the query schema](#overriding-the-nodeQuery-function)\n- [Using the nodeQuery method independantly](#)\n- [Scoping method to specific DOM node](#)\n\n**Query examples**\n- [Basic query](#basic-query)\n- [Find multiple instances of an attribute](#find-multiple-instances-of-attribute)\n- [Nested HTML values](#nested-HTML-values)\n- [Advanced Example](#advanced-Example)\n\n### Basic Examples\n\n#### Basic usage:\n\nLet's say that we have following the basic file structure:\n```\n.\n├── index.html\n├── Example.jsx\n└── scripts.jsx\n```\n\nThe examples below work under the assumption that `index.html` is a server-side templating file. (It might just as easily be something like `contact-widget.php`). It also assumed that `scripts.jsx` will be the file that gets compiled into your public facing JavaScript file (for example `scripts.min.js`) and then imported into your template.\n\n```\n// index.html\n\n\n\u003cbody\u003e\n  \u003cdiv data-component=\"Example\"\u003e\u003c/div\u003e\n\u003c/body\u003e\n```\n\n```\n// Example.jsx\n\n\nimport React from 'react';\n\n\nexport default function Example({ name = 'unknown user' }) {\n  return \u003cspan\u003eHello {name}\u003c/span\u003e;\n}\n\n```\n\n```\n// scripts.jsx\n\n\nimport Example from './Example.jsx';\nimport { render } from 'react-dom';\nimport connect from 'react-html-connect'\n\n\nconnect(render, \u003cTest /\u003e);\n```\n\nThe first parameter takes a render function. This will either be the `render` function from React DOM or Preact. Passing the `render` method allows you explicitly control what specific library (or version of that library) you want to use.\n\nThe second parameter takes the component itself. The name of the component will be converted into a string that is used to match the component to a specific `data-component` attribute. Note that the string is case-sensitive.\n\nThe examples above will output the following HTML: \n\n```\n\u003cbody\u003e\n  \u003cdiv data-component=\"Test\"\u003e\n    \u003cspan\u003eHello uknown user\u003c/span\u003e\n  \u003c/div\u003e\n\u003c/body\u003e\n```\n\n#### Passing props to components:\n\nIn addition you can pass instructions as an object to the query parameter inside the function. These instructions indicate what values from the HTML to pass to the component.\n\nThis instruction object uses a custom schema loosely inspired by GraphQl. See the 'Query Schema' heading below for full instructions on writing a query. \n\nHowever, for this specific example you should know only that name of the key in the object indicates the name of the data attribute on the HTML node itself ('data-name' in this case). While the value indicates how the value of this attribute should be parsed. The following example will generate `\u003cspan\u003eHello John Smith\u003c/span\u003e`:\n\n```\n// index.html\n\n\n\u003cbody\u003e\n  \u003cdiv data-component=\"Example\" data-name=\"John Smith\"\u003e\u003c/div\u003e\n\u003c/body\u003e\n```\n\n```\n// scripts.jsx\n\n\nimport Test from './Test.jsx';\nimport { render } from 'react-dom';\nimport connect from 'react-html-connect'\n\n\nconnect(render, \u003cExample /\u003e, { name: 'string' });\n```\n\n#### Initialising multiple components:\n\nWhen looking at the example above it becomes clear how instances of React components can be repeated to generate different outputs based on server-side values:\n\n```\n// index.html\n\n\u003cbody\u003e\n  \u003cdiv data-component=\"Example\"\u003e\u003c/div\u003e\n  \u003cdiv data-component=\"Example\" data-name=\"John Smith\"\u003e\u003c/div\u003e\n  \u003cdiv data-component=\"Example\" data-name=\"Jane Doe\"\u003e\u003c/div\u003e\n  \u003cdiv data-component=\"Example\" data-name=\"Billy Johnson\"\u003e\u003c/div\u003e\n  \u003cdiv data-component=\"Example\" data-name=\"Sarah Jackson\"\u003e\u003c/div\u003e\n\u003c/body\u003e\n```\n\n```\n// scripts.jsx\n\nimport Example from './Example.jsx';\nimport { render } from 'react-dom';\nimport connect from 'react-html-connect'\n\n\nconnect(render, \u003cExample /\u003e, { name: 'string' });\n```\n\n#### Overriding the query schema.\n\nYou can override the query parameter by manually passing a function. This allows you the flexibility to edit or customise props passed to the component. The following example will generate `\u003cspan\u003eHello Mr. John Smith\u003c/span\u003e`:\n\n\n```\n// scripts.jsx\n\nimport Example from './Example.jsx';\nimport { render } from 'react-dom';\nimport connect from 'react-html-connect'\n\n\nconst title = 'Mr. '\n\nconnect(\n  render, \n  \u003cExample /\u003e, \n  (node) =\u003e {\n    const rawName = node.getAttribute('data-name');\n    return { name: title + rawName };\n  },\n);\n```\n\n#### Using the nodeQuery method independantly.\n\nUnderlying the connect function's _query_ parameter is a function called `nodeQuery` that creates the props object from the query instructions.\n\nNote that this function can be destructed from the package and used independantly. This is very useful when combining the ease of _query_ parameter object with the flexibility of passing a function. The above example can also be written as follows:\n\n```\n// scripts.jsx\n\nimport Example from './Example.jsx';\nimport { render } from 'react-dom';\nimport { nodeQuery }, connect from 'react-html-connect'\n\n\nconst title = 'Mr. '\n\nconnect(\n  render, \n  \u003cExample /\u003e, \n  (node) =\u003e {\n    const rawName = nodeQuery(node, { name: 'string' });\n    return { name: title + rawName };\n  },\n);\n```\n\nThe API is as folows: \nnodeQuery(_query_, _node_)\n- `query \u003cObject\u003e`\n- `scope \u003cHTMLelement\u003e`\n\n\n#### Scoping method to specific DOM node.\n\nBy default the connect function searches the entire DOM via the `window.document` tree. \n\nHowever you can narrow the scope to a specific DOM node by passing that node as inside the options parameter. This is usually encouraged to improve performance or to mitigate conflicting attribute names:\n\n```\n// index.html\n\n\u003cbody\u003e\n  \u003cdiv id=\"initialise\"\u003e\n    \u003cdiv data-component=\"Example\"\u003e\u003c/div\u003e\n  \u003c/div\u003e\n  \u003cdiv id=\"ignore\"\u003e\n    \u003cdiv data-component=\"Example\"\u003e\u003c/div\u003e\n  \u003c/div\u003e\n\u003c/body\u003e\n```\n\n```\n// index.jsx\n\n\nimport Example from './Example.jsx';\nimport { render } from 'react-dom';\nimport connect from 'react-html-helpers'\n\n\nconnect(\n  render, \n  \u003cExample /\u003e, \n  {}, \n  {\n    scope: document.getElementById('initialise')\n  }\n);\n```\n\n### Examples involving the query schema\n\n#### Basic query\n```\n// HTML\n\n\n\u003cbody\u003e\n  \u003cdiv data-age=\"30\"\u003e\n\u003c/body\u003e\n```\n\n```\n// index.js\n\n\nimport { nodeQuery } from 'react-html-connect'\n\n\nconsole.log(nodeQuery({ age: 'number' }))\n```\n\n```\n// console output\n\n\n{ age: 30 }\n```\n\nYou will see that key in the `query` object is used to find the `data-value` HTML node. Since all custom attributes need to have `data-` prefixed to them, you do not need to repeat `data-` in the key itself. Once the attribute is located the value inside the `query` object determines how to parse its contents. In this example we passed 'number', which means that it is converted to a number via `parseFloat()`.\n\nValid parse commands are as follows:\n- `'string'` returns the attribute value as a string.\n- `'number'` returns the attribute value as a number (can include decimals).\n- `'boolean'` returns `true` or `false`, depending whether the attribute exists.\n- `'json'` returns the attribute value as a JavaScript object (automatically decodes HTML entities).\n- `'innerHTML'` returns the innerHTML of the node that the attribute is attached to.\n- `'outerHTML'` returns the outerHTML of the node that the attribute is attached to.\n- `null` return the node itself.\n\nLastly, you can also pass a function as a value. This function will then use the HTML node itself as its first parameter. For example the following will return `600`:\n\n```\nnode =\u003e parseInt(node.getAttribute('data-value')) * 2\n```\n\nThis means that in the example below the query will return the following:\n```\n// HTML\n\n\n\u003cbody\u003e\n  \u003cdiv data-age=\"30\" data-name=\"John Smith\" data-male data-family='{ \"brother\": \"Billy Johnson\", \"sister\": \"Jane Doe\" }'\u003eHello\u003c/div\u003e\n\u003c/body\u003e\n```\n\n```\n// index.js\n\n\nimport { nodeQuery } from 'react-html-connect'\n\n\nconst query = {\n  age: 'number',\n  name: 'string',\n  male: 'boolean',\n  greeting: 'innerHTML'\n  family: 'json'\n};\n\n\nconsole.log(nodeQuery(query))\n```\n\n```\n// console output\n\n\n{\n  age: 30,\n  name: 'John Smith',\n  male: true,\n  greeting: 'Hello',\n  family: { brother: 'Billy Johnson', sister: 'Jane Doe'}\n}\n```\n\nNote that true to the `JSON.parse()` method, `'json'` is also able to parse an array:\n```\n// HTML\n\n\n\u003cbody\u003e\n  \u003cdiv data-family='[\"Billy Johnson\", \"Jane Doe\"]'\u003e\u003c/div\u003e\n\u003c/body\u003e\n```\n\n```\n// index.js\n\n\nimport { nodeQuery } from 'react-html-connect'\n\n\nconsole.log(nodeQuery({ family: 'json' }))\n```\n\n```\n// console output\n\n\n{ family: ['Billy Johnson', 'Jane Doe'] }\n```\n\nIn addition, you will notice that the values of `family`, in both examples, are encapsulated in single quotes. This is generally not regarded as good HTML practice since HTML attributes should be encased in double quotes. However, since `JSON.parse()` only accepts double quotes, the outer quotes are swapped as single quotes to not conflict with the inner JSON double quotes. \n\nThis is a quick way to get a JSON string into JavaScript. However, as mentioned this goes against the standard HTML convention and it also means that they might conflict with any single quotes inside the JSON values themselves. Fortunately, we are able to escape double quotes with [HTML entities](https://developer.mozilla.org/en-US/docs/Glossary/Entity). This means that we are able to write the above as follows:\n```\n// HTML\n\n\n\u003cbody\u003e\n  \u003cdiv data-male data-family=\"{ \u0026quot;brother\u0026quot;: \u0026quot;Billy Johnson\u0026quot;, \u0026quotsister\u0026quot: \u0026quotJane Doe\u0026quot }'\u003e\u003c/div\u003e\n\u003c/body\u003e\n```\n\n```\n// index.js\n\n\nimport { nodeQuery } from 'react-html-connect'\n\n\nconsole.log(nodeQuery({ family: 'json' }))\n```\n\n```\n// console output\n\n\n{ family: ['Billy Johnson', 'Jane Doe'] }\n```\n\nIt's neither pretty nor readable. However we can use an online tool like [Freeformatter](https://www.freeformatter.com/html-escape.html) to encode our string into HTML entities, and also decode them for  debugging or editing. In addition most server-side templating have HTML entity escape functions that you can pass the string through. For example:\n\n- Jekyll: `{{ '{ \"brother\": \"Billy Johnson\", \"sister\": \"Jane Doe\" }' | escape }}`\n- Wordpress: `esc_html('{ \"brother\": \"Billy Johnson\", \"sister\": \"Jane Doe\" }')`\n\n#### Props from child nodes\n\nIt's easy to see how the above `query` parameter can be used to create React component from scratch. However, going further there are cases where you might want some of the content to be rendered by the server-side templating before the JavaScript fires either for performance reasons or SEO concerns. \n\nIt is possible to render HTML server-side and then infer values from it to be used in a React component (often used to replace or enhance the original markup). Luckily the _query_ parameter not only scans the DOM node that a component is bound to but also all of it's children:\n\n```\n// HTML\n\n\n\u003cbody\u003e\n  \u003cdiv \u003e\n\t\u003ch1 data-name\u003eJohn Smith\u003c/h1\u003e\n    \u003cp data-bio data-male\u003e\u003cstrong\u003eJohn\u003c/strong\u003e is a male. His sister is \u003cem\u003eJane\u003c/em\u003e. His brother is \u003cem\u003eBilly\u003c/em\u003e. He is \u003cspan data-age\u003e30\u003c/span\u003e years old.\u003c/p\u003e\n  \u003c/div\u003e\n\u003c/body\u003e\n```\n\n```\n// index.js\n\n\nimport { nodeQuery } from 'react-html-connect'\n\nconst query = {\n  name: 'innerHTML',\n  age: node =\u003e parseInt(node.innerHTML),\n  male: 'boolean',\n  bio: 'outerHTML',\n}\n\n\nconsole.log(nodeQuery(query));\n```\n\n```\n// console output\n\n\n{ \n  name: 'John Smith',\n  male: true,\n  age: 30,\n  bio: '\u003cp data-bio data-male\u003e\u003cstrong\u003eJohn\u003c/strong\u003e is a male. His sister is \u003cem\u003eJane\u003c/em\u003e. His brother is \u003cem\u003eBilly\u003c/em\u003e. He is \u003cspan data-age\u003e30\u003c/span\u003e years old.\u003c/p\u003e'\n}\n```\n\n\nThese data attribute can be anywhere in the DOM tree since `scope` is set to `window.document` by default. This means that you need to be careful to use the same name for two different things (for example 'data-item', 'data-outer-item', data-inner-item, etc.)\n\n### Find multiple instances of attribute\n\nWe can instruct our query to collect all instances of `data-people` into an array by placing our query object as the first (and only) value in an array. The key of the array needs to correspond to the name of data attribute ('people' in the example below):\n\n```\n// index.HTML\n\n\n\u003cbody\u003e\n  \u003cdiv data-people\u003e\n    \u003ch1 data-name\u003eJohn Smith\u003c/h1\u003e\n    \u003cp data-bio data-male\u003e\u003cstrong\u003eJohn\u003c/strong\u003e is a male. His sister is \u003cem data-relatives\u003eJane\u003c/em\u003e. His brother is \u003cem data-relatives\u003eBilly\u003c/em\u003e. He is \u003cspan data-age\u003e30\u003c/span\u003e years old.\u003c/p\u003e\n  \u003c/div\u003e\n  \u003cdiv data-people\u003e\n    \u003ch1 data-name\u003eJane Doe\u003c/h1\u003e\n    \u003cp data-bio\u003e\u003cstrong\u003eJane\u003c/strong\u003e is a female. Her brothers are \u003cem data-relatives\u003eBilly\u003c/em\u003e and \u003cem data-relatives\u003eJohn\u003c/em\u003e. She is \u003cspan data-age\u003e30\u003c/span\u003e years old.\u003c/p\u003e\n  \u003c/div\u003e\n\u003c/body\u003e\n```\n\n\n```\n// index.js\n\n\nimport { nodeQuery } from 'react-html-connect'\n\n\nconst query = {\n  people: [\n    {\n      name: 'innerHTML',\n      age: node =\u003e parseInt(node.innerHTML)\n      bio: 'outerHTML',\n      relatives: ['innerHTML'],\n    }\n  ]\n}\n\n\nconsole.log(nodeQuery(query));\n```\n\n```\n// console output\n\n\n{ \n  people: [\n    {\n      name: 'John Smith',\n      male: true,\n      age: 30,\n      bio: '\u003cp data-bio data-male\u003e\u003cstrong\u003eJohn\u003c/strong\u003e is a male. His sister is \u003cem data-relatives\u003eJane\u003c/em\u003e. His brother is \u003cem data-relatives\u003eBilly\u003c/em\u003e. He is \u003cspan data-age\u003e30\u003c/span\u003e years old.\u003c/p\u003e'\n      relatives: ['Jane', 'Billy'],\n    },\n    { \n      name: 'Jane Doe',\n      male: false,\n      age: 24,\n      bio: '\u003cp data-bio\u003e\u003cstrong\u003eJane\u003c/strong\u003e is a female. Her brother is \u003cem data-relatives\u003eJohn\u003c/em\u003e. Her other brother is \u003cem data-relatives\u003eBilly\u003c/em\u003e. She is \u003cspan data-age\u003e24\u003c/span\u003e years old. \u003c/p\u003e',\n      relatives: ['John', 'Billy'],\n    }\n  ]\n```\n\n### Advanced Example\n\nNow that we've gone through all the above, let's end with an example highlighting all the aspects touched upon above:\n\n```\n// HTML\n\n\u003cbody\u003e\n  \u003cdiv data-component=\"Other\"\u003e\n    \u003cul\u003e\n      \u003cli data-people\u003eJohn Smith\u003c/li\u003e\n      \u003cli data-people\u003eJane Doe\u003c/li\u003e\n      \u003cli data-people\u003eBilly Johnson\u003c/li\u003e\n      \u003cli data-people\u003eSarah Jackson\u003c/li\u003e\n    \u003c/ul\u003e\n  \u003c/div\u003e\n  \u003cdiv data-component=\"People\"\u003e\n    \u003ch1 data-title\u003eClub Members\u003c/h1\u003e\n    \u003cdiv data-people data-id=\"001\"\u003e\n      \u003ch2 data-name\u003eJohn Smith\u003c/h2\u003e\n      \u003cp data-bio data-male\u003e\u003cstrong\u003eJohn\u003c/strong\u003e is a male. His sister is \u003cem data-relative\u003eJane\u003c/em\u003e. His brother is \u003cem data-relative\u003eBilly\u003c/em\u003e. He is \u003cspan data-age\u003e30\u003c/span\u003e years old. \u003c/p\u003e\n    \u003c/div\u003e\n    \u003cdiv data-people data-id=\"002\"\u003e\n      \u003ch2 data-name\u003eJane Doe\u003c/h2\u003e\n      \u003cdiv\u003e\u003cp data-bio\u003e\u003cstrong\u003eJane\u003c/strong\u003e is a female. Her brother is \u003cem data-relative\u003eJohn\u003c/em\u003e. Her other brother is \u003cem data-relative\u003eBilly\u003c/em\u003e. She is \u003cspan data-age\u003e24\u003c/span\u003e years old. \u003c/p\u003e\u003c/div\u003e\n    \u003c/div\u003e\n    \u003cdiv\u003eLoading button...\u003c/div\u003e\n   \u003c/div\u003e\n\u003c/body\u003e\n```\n\n```\n// scripts.jsx\n\nimport People from './People.jsx';\nimport Other from './Other.jsx';\nimport { render } from 'react-dom';\nimport connect from 'react-html-connect'\n\nconst peopleQuery = {\n  title: 'innerHTML',\n  people: [\n    {\n      id: number,\n      name: 'innerHTML',\n      age: node =\u003e parseInt(node.innerHTML)\n      bio: 'outerHTML',\n      relatives: ['innerHTML'],\n    }\n  ]\n}\n\nconst otherQuery = {\n  people: ['innerHTML'],\n}\n\n\nconnect(render, \u003cPeople /\u003e, peopleQuery)\nconnect(render, \u003cOther /\u003e, otherQuery)\n```\n\n```\n// People.jsx\n\nimport React from 'react';\n\n\nfunction People({ title, people }) {\n  const logToConsole = () =\u003e console.log(people.map(obj =\u003e obj.name));\n\n  const list = people.map(({name, bio, id }) =\u003e (\n    \u003cdiv key={id}\u003e\n      \u003ch2\u003e{name}\u003c/h2\u003e\n      \u003cdiv dangerouslySetInnerHTML={{ __html: bio }}\u003e\n    \u003c/div\u003e\n  ));\n\n  return (\n    \u003cdiv\u003e\n      \u003ch1\u003e{title}\u003c/h1\u003e\n      {list.length \u003e 0 ? list : null}\n    \u003c/div\u003e\n    \u003cdiv\u003e\n      \u003cbutton onClick={logToConsole}\u003eLog list of people to console\u003c/button\u003e\n  );\n}\n```\n--\u003e","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fschalkventer%2Freact-html-connector","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fschalkventer%2Freact-html-connector","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fschalkventer%2Freact-html-connector/lists"}