Linear Design Pillbar (Vue.js)

Simple Vue Pillbar. Allows you to create groups like radio buttons, or to select multiple pills.

Also threw in some CSS variable experimentation for kicks and giggles.

html

<div style="margin:16px;width: 300px;" class="container">
  <div class="mount"></div>
  <div class="mount"></div>
</div>


<div class="input"></div>
HTML

Css

:root {
  --selected-color: #106cc8;
  --active-color: #1e86ed;
}

$selected-color = #106cc8;
$active-color = #1e86ed;

html, body {
  margin:0px;
  height: 100%;
}
.container {
  .linear-pillbar {
    margin-top:8px;
  }
}
.linear-pillbar {
  font-family: 'Roboto', Arial;
  display: flex;
  border: 1px solid $selected-color;
  border: 1px solid var(--selected-color);
  min-height:32px;
  position:relative;
  border-radius:3px;
  .option {
    outline:none;
    font-size:1em;
    background:transparent;
    border:none;
    flex:1 1 auto;
    padding:4px;
    display:flex;
    align-items:center;
    justify-content:center;
    border-right: 1px solid $selected-color;
    border-right: 1px solid var(--selected-color);
    color:$selected-color;
    color:var(--selected-color);
    cursor:pointer;
    &.equal {
      flex:1;
    }
    &:hover, &:focus, &:active {
      color:$active-color;
      color:var(--active-color);
    }
    &.selected {
      background:$selected-color;
      background:var(--selected-color);
      color:white;
      border-right: 1px solid white;
      &:hover, &:focus, &:active {
        background:$active-color;
        background:var(--active-color);
      }
    }
    
    &:last-child {
      border-right:none;
    }
  }
}

.color-input {
  display:flex;
  flex-direction:column;
  width:300px;
  margin-left:16px;
  input {
    margin-bottom: 8px;
    padding:4px;
  }
}
CSS

JavaScript

const LinearPillbar = {
  el:".mount",
  template:`
    <div class="linear-pillbar">
      <button class="option" v-for="option of options" :class="{selected:option.selected, equal: equalWidth}" @click="select(option)">
        <i class="material-icons" v-if="option.icon">{{option.icon}}</i>
        <div v-else>{{option.name}}</div>
      </button>
    </div>
  `,
  props: {
    options: {
      type:Array,
      default:() => []
    },
    equalWidth: {
      type:Boolean,
      default:false
    },
    mainColor: {
      type:String,
      default:'#106cc8'
    },
    highlightColor: {
      type:String,
      default:'#1e86ed'
    },
  },
  mounted() {
    document.documentElement.style.setProperty(`--selected-color`, this.mainColor);
    document.documentElement.style.setProperty(`--active-color`, this.highlightColor);
  },
  methods: {
    select(option) {
      if(option.group && !option.selected) {
        Vue.set(option, 'selected', !option.selected);
        for(let otherOption of this.options) {
          if(otherOption.name !== option.name && option.group === otherOption.group) {
            Vue.set(otherOption, 'selected', false); 
          }
        }   
      }
      else if(!option.group) {
        Vue.set(option, 'selected', !option.selected);
      }
      this.$emit('change', this.options);
    }
  },
  propsData: {
    options: [
      {name:'Source', group:'type'},
      {name:'Target', group:'type'},
      {name:'Aa'}
    ],
    equalWidth:true,
 //   mainColor:'#10c86c',
 //   highlightColor:'#1eed86'
  }
};

new Vue(LinearPillbar);
//LinearPillbar.propsData.mainColor = 'red';//changing this for one component changes it for all
//LinearPillbar.propsData.highlightColor = 'pink';
LinearPillbar.propsData.options = [
      {name:'Source', group:'type'},
      {name:'Target', group:'type'},
      {name:'Aa'}
    ]
new Vue(LinearPillbar);

let ColorInput = {
  el:'.input',
  template:`
    <div class="color-input">
      Change CSS Variables Here
      <input placeholder="main color" v-model="mainColor" @input="updateMainColor">
      <input placeholder="hover color" v-model="hoverColor" @input="updateHoverColor">
    </div>`,
  data() {
    return {
      mainColor: '',
      hoverColor: ''
    }
  },
  methods: {
    updateMainColor() {
      document.documentElement.style.setProperty(`--selected-color`, this.mainColor);
    },
    updateHoverColor() {
      document.documentElement.style.setProperty(`--active-color`, this.hoverColor)
    }
  }
}

new Vue(ColorInput);
JavaScript

Author

Hyrum White

Demo