JSFiddle - React, Tailwind, and code Playground

HTML

<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<div class="container" id="vue-root">
  <div class="row">
    <div class="col-xs-12">
      <h1>A JSON Tree View Component in Vue.js</h1>      
    </div>  
  </div>

  <div class="row">
    <div class="col-xs-12">
      <h2>
      Simple JSON <small>opened until depth of 7</small>
      </h2>
      <div class="well">
        <tree-view :data="sampleData" link=true max-depth="7" ></tree-view>>
      </div>      
    </div>
  </div>
  
  <div class="row">
    <div class="col-xs-12">
      <h2>
        Complicated JSON <small>opened until depth of 3</small>
      </h2>
      <div class="well">
        <tree-view :data="sampleData1" max-depth="3"></tree-view>
      </div>    
    </div>
  </div>
  

</div>

CSS

/* The Tree View should only fill out available space, scroll when 
   necessary.
*/


.tree-view-item {
  font-family: monospace;
  font-size: 14px;
  margin-left: 18px;
}

.tree-view-wrapper {
  overflow: auto;
}

/* Find the first nested node and override the indentation */
.tree-view-item-root > .tree-view-item-leaf > .tree-view-item {
  margin-left: 0;
}

/* Root node should not be indented */
.tree-view-item-root {
  margin-left: 0;
}

.tree-view-item-node {
  cursor: pointer;
  position: relative;
  white-space: nowrap;
}

.tree-view-item-leaf {
  white-space: nowrap;
}

.tree-view-item-key {
  font-weight: bold;
}

.tree-view-item-key-with-chevron {
  padding-left: 14px;
}


.tree-view-item-key-with-chevron.opened::before {
    top:4px;
    transform: rotate(90deg);  
    -webkit-transform: rotate(90deg);
}

.tree-view-item-key-with-chevron::before {
    color: #444;
    content: '\25b6';
    font-size: 10px;
    left: 1px;
    position: absolute;
    top: 3px;
    transition: -webkit-transform .1s ease;
    transition: transform .1s ease;
    transition: transform .1s ease, -webkit-transform .1s ease;
    -webkit-transition: -webkit-transform .1s ease;
}

.tree-view-item-hint {
  color: #ccc
}

Babel + JSX

Vue.component("tree-view-item", Vue.extend({
	name: "tree-view-item",
  props: ["data", "max-depth", "current-depth"],
  data: function(){
  	return {
    	open: this.currentDepth < this.maxDepth
    }
  },
  methods: {
  	isOpen: function(){
    	return this.isRootObject(this.data) || this.open;
    },
    toggleOpen:function(){
    	this.open = !this.open;
    },    
  	isObject: function(value){
    	return value.type === 'object';
    },
  	isArray: function(value){
    	return value.type === 'array';
    },
    isValue: function(value){
    	return value.type === 'value';
    },
    getKey: function(value){
    	if (_.isInteger(value.key)) {
      	return value.key+":";
      } else {
	      return "\""+ value.key + "\":";	
      }
    },    
    getValue: function(value){
    	if (_.isNumber(value.value)) {
      	return value.value
      }
      if (_.isNull(value.value)) {
      	return "null"
      }
      if (_.isString(value.value)) {}
    	return "\""+value.value+"\"";
    },
    isRootObject: function(value){
    	return value.isRoot;
    }
  },
  template:`
  	<div class="tree-view-item">
    	<div v-if="isObject(data)" class="tree-view-item-leaf">
      	<div class="tree-view-item-node" @click.stop="toggleOpen()">         	
       		<span :class="{opened: isOpen()}" v-if="!isRootObject(data)" class="tree-view-item-key tree-view-item-key-with-chevron">{{getKey(data)}}</span>
          <span class="tree-view-item-hint" v-show="!isOpen() && data.children.length === 1">{{data.children.length}} property</span>
          <span class="tree-view-item-hint" v-show="!isOpen() && data.children.length !== 1">{{data.children.length}} properties</span>
        </div>
				<tree-view-item :max-depth="maxDepth" :current-depth="currentDepth+1" v-show="isOpen()" v-for="child in data.children" :data="child"></tree-view-item>
      </div>
    	<div v-if="isArray(data)" class="tree-view-item-leaf">
      	<div class="tree-view-item-node" @click.stop="toggleOpen()">
    ...