diff --git a/ui/.babelrc b/ui/.babelrc
new file mode 100644
index 00000000..3de5edda
--- /dev/null
+++ b/ui/.babelrc
@@ -0,0 +1,16 @@
+{
+ "sourceMaps": "both",
+ "presets": [
+ "react",
+ "es2015"
+ ],
+ "plugins": [
+ "react-hot-loader/babel",
+ "add-module-exports",
+ "transform-exponentiation-operator",
+ "syntax-async-functions",
+ ["transform-object-rest-spread", {
+ "useBuiltIns": true
+ }]
+ ]
+}
diff --git a/ui/.eslintignore b/ui/.eslintignore
new file mode 100644
index 00000000..b1d4c644
--- /dev/null
+++ b/ui/.eslintignore
@@ -0,0 +1,3 @@
+/node_modules
+coverage
+.nyc_output
\ No newline at end of file
diff --git a/ui/.eslintrc b/ui/.eslintrc
new file mode 100644
index 00000000..55e4244d
--- /dev/null
+++ b/ui/.eslintrc
@@ -0,0 +1,29 @@
+{
+ "extends": "semistandard",
+ "parser": "babel-eslint",
+ "parserOptions": {
+ "ecmaVersion": 7,
+ "ecmaFeatures": {
+ "jsx": true
+ },
+ "sourceType": "module"
+ },
+ "plugins": [
+ "babel",
+ "react"
+ ],
+ "rules": {
+ "generator-star-spacing": 0,
+ "babel/generator-star-spacing": 1,
+ "space-before-function-paren": [2, "never"],
+ "react/jsx-uses-react": 2,
+ "react/jsx-uses-vars": 2,
+ "react/react-in-jsx-scope": 2,
+ "object-curly-newline": ["error", {
+ "minProperties": 1
+ }],
+ "sort-vars": ["error", {
+ "ignoreCase": true
+ }]
+ }
+}
diff --git a/ui/.tern-project b/ui/.tern-project
new file mode 100644
index 00000000..22bab84c
--- /dev/null
+++ b/ui/.tern-project
@@ -0,0 +1,15 @@
+{
+ "libs": [
+ "ecmascript",
+ "browser"
+ ],
+ "plugins": {
+ "doc_comment": true,
+ "local-scope": true,
+ "jsx": true,
+ "node": true,
+ "webpack": {
+ "configPath": "./webpack/index.js"
+ }
+ }
+}
\ No newline at end of file
diff --git a/ui/README.md b/ui/README.md
new file mode 100644
index 00000000..bb78c652
--- /dev/null
+++ b/ui/README.md
@@ -0,0 +1 @@
+# Joyent Dashboard UI Framework
diff --git a/ui/docs/components.js b/ui/docs/components.js
new file mode 100644
index 00000000..e69de29b
diff --git a/ui/docs/index.js b/ui/docs/index.js
new file mode 100644
index 00000000..af547af9
--- /dev/null
+++ b/ui/docs/index.js
@@ -0,0 +1,17 @@
+const ReactDOM = require('react-dom');
+const React = require('react');
+
+const render = () => {
+ const Root = require('./root');
+
+ ReactDOM.render(
+ ,
+ document.getElementById('root')
+ );
+};
+
+render();
+
+if (module.hot) {
+ module.hot.accept('./root', render);
+}
diff --git a/ui/docs/root.js b/ui/docs/root.js
new file mode 100644
index 00000000..10bb9624
--- /dev/null
+++ b/ui/docs/root.js
@@ -0,0 +1,16 @@
+const React = require('react');
+const ReactHotLoader = require('react-hot-loader');
+const Button = require('../src/button/readme.md');
+const InnerHTML = require('dangerously-set-inner-html');
+
+const {
+ AppContainer
+} = ReactHotLoader;
+
+module.exports = () => {
+ return (
+
+
+
+ );
+};
diff --git a/ui/package.json b/ui/package.json
new file mode 100644
index 00000000..dc34b61a
--- /dev/null
+++ b/ui/package.json
@@ -0,0 +1,67 @@
+{
+ "name": "joyent-dashboard-frontend",
+ "version": "1.0.0",
+ "private": true,
+ "license": "private",
+ "scripts": {
+ "start": "webpack-dev-server --open --config webpack/index.js",
+ "lint": "eslint .",
+ "test": "NODE_ENV=test nyc ava test/*.js --verbose",
+ "build": "NODE_ENV=production webpack --config webpack/index.js",
+ "clean-static": "sh scripts/clean-static.sh",
+ "build-docs-static": "sh scripts/build-docs-static.sh"
+ },
+ "dependencies": {
+ "react": "^15.3.2"
+ },
+ "devDependencies": {
+ "ava": "^0.16.0",
+ "babel-core": "^6.17.0",
+ "babel-eslint": "^7.0.0",
+ "babel-loader": "^6.2.5",
+ "babel-plugin-add-module-exports": "^0.2.1",
+ "babel-plugin-syntax-async-functions": "^6.13.0",
+ "babel-plugin-transform-object-rest-spread": "^6.16.0",
+ "babel-preset-es2015": "^6.16.0",
+ "babel-preset-react": "^6.16.0",
+ "babel-register": "^6.16.3",
+ "css-loader": "^0.25.0",
+ "dangerously-set-inner-html": "^1.0.0",
+ "enzyme": "^2.5.1",
+ "eslint": "^3.8.1",
+ "eslint-config-semistandard": "^7.0.0",
+ "eslint-config-standard": "^6.2.0",
+ "eslint-plugin-babel": "^3.3.0",
+ "eslint-plugin-promise": "^3.3.0",
+ "eslint-plugin-react": "^6.4.1",
+ "eslint-plugin-standard": "^2.0.1",
+ "extract-text-webpack-plugin": "^2.0.0-beta.4",
+ "html-loader": "^0.4.4",
+ "json-loader": "^0.5.4",
+ "nyc": "^8.3.1",
+ "postcss-cssnext": "^2.8.0",
+ "postcss-loader": "^1.0.0",
+ "pre-commit": "^1.1.3",
+ "react-addons-test-utils": "^15.3.2",
+ "react-dom": "^15.3.2",
+ "react-hot-loader": "^3.0.0-beta.6",
+ "react-router": "^4.0.0-alpha.4",
+ "style-loader": "^0.13.1",
+ "webpack": "^2.1.0-beta.25",
+ "webpack-dev-server": "^1.16.2",
+ "webpack-shell-plugin": "^0.4.3"
+ },
+ "ava": {
+ "failFast": true,
+ "cache": false,
+ "require": [
+ "babel-register"
+ ],
+ "babel": "inherit"
+ },
+ "pre-commit": [
+ "lint",
+ "test",
+ "coverage"
+ ]
+}
diff --git a/ui/scripts/build-docs-static.sh b/ui/scripts/build-docs-static.sh
new file mode 100644
index 00000000..09b0fb45
--- /dev/null
+++ b/ui/scripts/build-docs-static.sh
@@ -0,0 +1,3 @@
+echo $(pwd)
+# cp -r ../static/* ../docs/static/
+# mv ../docs/static/index.html ../docs/
\ No newline at end of file
diff --git a/ui/scripts/clean-static.sh b/ui/scripts/clean-static.sh
new file mode 100644
index 00000000..e69de29b
diff --git a/ui/src/base/index.js b/ui/src/base/index.js
new file mode 100644
index 00000000..32dd9ac6
--- /dev/null
+++ b/ui/src/base/index.js
@@ -0,0 +1,5 @@
+const React = require('react');
+
+module.exports = () => {
+ return null;
+};
diff --git a/ui/src/button/index.js b/ui/src/button/index.js
new file mode 100644
index 00000000..d53e09a0
--- /dev/null
+++ b/ui/src/button/index.js
@@ -0,0 +1,16 @@
+const React = require('react');
+const styles = require('./style.css');
+
+module.exports = ({
+ disabled = false,
+ children
+}) => {
+ return (
+
+ );
+};
diff --git a/ui/src/button/readme.md b/ui/src/button/readme.md
new file mode 100644
index 00000000..5cd85730
--- /dev/null
+++ b/ui/src/button/readme.md
@@ -0,0 +1,29 @@
+# `