diff --git a/.gitignore b/.gitignore
index fce7d1d993be4..024baa37c4c54 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,13 +13,7 @@ docs/code
docs/_site
docs/.sass-cache
docs/css/react.css
-docs/js/.module-cache
-docs/js/JSXTransformer.js
-docs/js/react.min.js
-docs/js/docs.js
-docs/js/jsx-compiler.js
-docs/js/live_editor.js
-docs/js/examples
+docs/js/*
docs/downloads
examples/shared/*.js
diff --git a/docs/_js/html-jsx-lib.js b/docs/_js/html-jsx-lib.js
new file mode 100644
index 0000000000000..9029c53ac2002
--- /dev/null
+++ b/docs/_js/html-jsx-lib.js
@@ -0,0 +1,482 @@
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * This is a very simple HTML to JSX converter. It turns out that browsers
+ * have good HTML parsers (who would have thought?) so we utilise this by
+ * inserting the HTML into a temporary DOM node, and then do a breadth-first
+ * traversal of the resulting DOM tree.
+ */
+;(function(global) {
+ 'use strict';
+
+ // https://developer.mozilla.org/en-US/docs/Web/API/Node.nodeType
+ var NODE_TYPE = {
+ ELEMENT: 1,
+ TEXT: 3,
+ COMMENT: 8
+ };
+ var ATTRIBUTE_MAPPING = {
+ 'for': 'htmlFor',
+ 'class': 'className'
+ };
+
+ /**
+ * Repeats a string a certain number of times.
+ * Also: the future is bright and consists of native string repetition:
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeat
+ *
+ * @param {string} string String to repeat
+ * @param {number} times Number of times to repeat string. Integer.
+ * @see http://jsperf.com/string-repeater/2
+ */
+ function repeatString(string, times) {
+ if (times === 1) {
+ return string;
+ }
+ if (times < 0) { throw new Error(); }
+ var repeated = '';
+ while (times) {
+ if (times & 1) {
+ repeated += string;
+ }
+ if (times >>= 1) {
+ string += string;
+ }
+ }
+ return repeated;
+ }
+
+ /**
+ * Determine if the string ends with the specified substring.
+ *
+ * @param {string} haystack String to search in
+ * @param {string} needle String to search for
+ * @return {boolean}
+ */
+ function endsWith(haystack, needle) {
+ return haystack.slice(-needle.length) === needle;
+ }
+
+ /**
+ * Trim the specified substring off the string. If the string does not end
+ * with the specified substring, this is a no-op.
+ *
+ * @param {string} haystack String to search in
+ * @param {string} needle String to search for
+ * @return {string}
+ */
+ function trimEnd(haystack, needle) {
+ return endsWith(haystack, needle)
+ ? haystack.slice(0, -needle.length)
+ : haystack;
+ }
+
+ /**
+ * Convert a hyphenated string to camelCase.
+ */
+ function hyphenToCamelCase(string) {
+ return string.replace(/-(.)/g, function(match, chr) {
+ return chr.toUpperCase();
+ });
+ }
+
+ /**
+ * Determines if the specified string consists entirely of whitespace.
+ */
+ function isEmpty(string) {
+ return !/[^\s]/.test(string);
+ }
+
+ /**
+ * Determines if the specified string consists entirely of numeric characters.
+ */
+ function isNumeric(input) {
+ return input !== undefined
+ && input !== null
+ && (typeof input === 'number' || parseInt(input, 10) == input);
+ }
+
+ var HTMLtoJSX = function(config) {
+ this.config = config || {};
+
+ if (this.config.createClass === undefined) {
+ this.config.createClass = true;
+ }
+ if (!this.config.indent) {
+ this.config.indent = ' ';
+ }
+ if (!this.config.outputClassName) {
+ this.config.outputClassName = 'NewComponent';
+ }
+ };
+ HTMLtoJSX.prototype = {
+ /**
+ * Reset the internal state of the converter
+ */
+ reset: function() {
+ this.output = '';
+ this.level = 0;
+ },
+ /**
+ * Main entry point to the converter. Given the specified HTML, returns a
+ * JSX object representing it.
+ * @param {string} html HTML to convert
+ * @return {string} JSX
+ */
+ convert: function(html) {
+ this.reset();
+
+ // It turns out browsers have good HTML parsers (imagine that).
+ // Let's take advantage of it.
+ var containerEl = document.createElement('div');
+ containerEl.innerHTML = '\n' + this._cleanInput(html) + '\n';
+
+ if (this.config.createClass) {
+ if (this.config.outputClassName) {
+ this.output = 'var ' + this.config.outputClassName + ' = React.createClass({\n';
+ } else {
+ this.output = 'React.createClass({\n';
+ }
+ this.output += this.config.indent + 'render: function() {' + "\n";
+ this.output += this.config.indent + this.config.indent + 'return (\n';
+ }
+
+ if (this._onlyOneTopLevel(containerEl)) {
+ // Only one top-level element, the component can return it directly
+ // No need to actually visit the container element
+ this._traverse(containerEl);
+ } else {
+ // More than one top-level element, need to wrap the whole thing in a
+ // container.
+ this.output += this.config.indent + this.config.indent + this.config.indent;
+ this.level++;
+ this._visit(containerEl);
+ }
+ this.output = this.output.trim() + '\n';
+ if (this.config.createClass) {
+ this.output += this.config.indent + this.config.indent + ');\n';
+ this.output += this.config.indent + '}\n';
+ this.output += '});';
+ }
+ return this.output;
+ },
+
+ /**
+ * Cleans up the specified HTML so it's in a format acceptable for
+ * converting.
+ *
+ * @param {string} html HTML to clean
+ * @return {string} Cleaned HTML
+ */
+ _cleanInput: function(html) {
+ // Remove unnecessary whitespace
+ html = html.trim();
+ // Ugly method to strip script tags. They can wreak havoc on the DOM nodes
+ // so let's not even put them in the DOM.
+ html = html.replace(/
+
+