diff --git a/rollup.config.js b/rollup.config.js
index b506580..bc532c8 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -1,48 +1,51 @@
-import resolve from 'rollup-plugin-node-resolve';
-import commonjs from 'rollup-plugin-commonjs';
-import babel from 'rollup-plugin-babel';
-import vue from 'rollup-plugin-vue';
-import autoprefixer from 'autoprefixer';
-import { terser } from 'rollup-plugin-terser';
-import pkg from './package.json';
+import resolve from "rollup-plugin-node-resolve";
+import commonjs from "rollup-plugin-commonjs";
+import babel from "rollup-plugin-babel";
+import vue from "rollup-plugin-vue";
+import autoprefixer from "autoprefixer";
+import { terser } from "rollup-plugin-terser";
+import pkg from "./package.json";
 
 const babelOptions = {
-	extensions: ['.js', '.jsx', '.es6', '.es', '.mjs', '.vue', '.ts'],
-}
+  extensions: [".js", ".jsx", ".es6", ".es", ".mjs", ".vue", ".ts"]
+};
 
 export default [
-	// browser-friendly UMD build
-	{
-		input: pkg.main,
-		output: {
-			name: pkg.name,
-			file: pkg.browser,
-			format: 'umd',
-			sourcemap: false
-		},
-		plugins: [
-			resolve(),
-			commonjs(),
-			vue({
-				postcssPlugins: [autoprefixer()]
-			}),
-			babel(babelOptions),
-			//terser()
-		]
-	},
-	{
-		input: pkg.main,
-		output: [
-			{ file: pkg.module, format: 'es' }
-		],
-		plugins: [
-			resolve(),
-			commonjs(),
-			vue({
-				postcssPlugins: [autoprefixer ()]
-			}),
-			babel(babelOptions),
-			// terser()
-		]
-	}
+  // browser-friendly UMD build
+  {
+    input: pkg.main,
+    output: {
+      name: pkg.name,
+      file: pkg.browser,
+      exports: "named",
+      format: "umd",
+      sourcemap: false
+    },
+    plugins: [
+      resolve(),
+      commonjs(),
+      vue({
+        postcssPlugins: [autoprefixer()]
+      }),
+      babel(babelOptions),
+      terser()
+    ]
+  },
+  {
+    input: pkg.main,
+    output: [
+      {
+        exports: "named",
+        file: pkg.module,
+        format: "es"
+      }
+    ],
+    plugins: [
+      resolve(),
+      commonjs(),
+      vue({
+        postcssPlugins: [autoprefixer()]
+      }),
+      babel(babelOptions)    ]
+  }
 ];
diff --git a/src/RenderlessVueSelect.vue b/src/RenderlessVueSelect.vue
index d636bec..1679366 100644
--- a/src/RenderlessVueSelect.vue
+++ b/src/RenderlessVueSelect.vue
@@ -4,6 +4,9 @@
  * [1] - ENHACEMENT: Add highlighted substrings (like the wesbos course)
  * [2] - Loading states and async work compatibility out-of-the-boz
  */
+const ATTRS_NAMESPACE = "data-renderless-vue-select";
+const SUPPORTS_SCROLLBEHAVIOR = 'scrollBehavior' in document.documentElement.style
+
 export default {
   name: "renderless-vue-select",
   props: {
@@ -12,125 +15,157 @@ export default {
       default: null
     },
     options: {
-      type: [Array],
+      type: Array,
       required: true
-      // we use a serializer to validate
     },
     /**
      * Default Filter by start matching, pass custom filters or fuzzy search engin like Fuse.js
      */
     filterFunction: {
       type: Function,
-      default: (query, options) => {
-        return options.filter(o => o.label.toLowerCase().startsWith(query.toLowerCase()))
+      default: (query, options, currentValue) => {
+        if (query === "" || query === currentValue.label) {
+          return options;
+        } else {
+          return options.filter(o =>
+            o.label.toLowerCase().startsWith(query.toLowerCase())
+          );
+        }
       }
+    },
+    /**
+     * Keeping state open after selecting option by click
+     * or keyboard, also after clicking outside the list
+     */
+    keepOpen: {
+      type: Boolean,
+      default: true
     }
   },
   model: {
     prop: "value",
     event: "select"
   },
-  data(){
+  data() {
     return {
-      query: '',
-      isOpen: false,
+      query: "",
+      isOpen: this.keepOpen ? true : false,
       highlightedIndex: 0,
-    }
+      selectedIndex: null
+    };
   },
   computed: {
     // [check if should allow bad option formating and serialize or enforce a proper format]
     serializedValue() {
-      if( typeof this.value === "string" || this.value === null){
-        return {label: this.value, value: this.value}
-      };
+      if (typeof this.value === "string" || this.value === null) {
+        return {
+          label: this.value,
+          value: this.value
+        };
+      }
 
-      if (this._validateFormat(this.value)){
-        return this.value
+      if (this._validateFormat(this.value)) {
+        return this.value;
       } else {
-        throw new Error("Label and value are required keys in your value object")
+        throw new Error(
+          "Label and value are required keys in your value object"
+        );
       }
     },
     // to allow ["option", "adasdad"] source when really it should be [{"label", "value"}]
-    serializedOptions(){
-      if( typeof this.options[0] === "string"){
-        console.warn('We accept this but you should use {label: "Label", value: "Value} since it matches the native format')
+    serializedOptions() {
+      if (typeof this.options[0] === "string") {
+        console.warn(
+          'We accept this but you should use {label: "Label", value: "Value} since it matches the native format'
+        );
         /**
          * If no value provided, value === "textContent2"of options as per spec
          * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select
          */
-        return this.options.map((o,i) => ({label: o, value: o}))
+        return this.options.map((o, i) => ({ label: o, value: o }));
       }
 
       // we optimistically hope if the first option matches the rest as
       // it is expensive to be validating long arrays
-      if(this._validateFormat(this.options[0])
-      ) {
-        return this.options
+      if (this._validateFormat(this.options[0])) {
+        return this.options;
       } else {
-        throw new Error("Label and value are required keys in your option object")
+        throw new Error(
+          "Label and value are required keys in your option object"
+        );
       }
     },
-    filteredOptions(){
+    filteredOptions() {
       // [1] [2]
-      return this.filterFunction(this.query, this.serializedOptions);
+      return this.filterFunction(
+        this.query,
+        this.serializedOptions,
+        this.serializedValue
+      );
     }
   },
   watch: {
-    value(newVal){
-      if(!this.serializedValue || (this.serializedValue && this.serializedValue.label === null)){
-        this.query = ""
-      } else {
-        this.query = this.serializedValue.label;
-      }
+    value() {
+      this._updateQuery(this.serializedValue);
+      this._setSelectedIndex();
     },
-    query(typedValue){
-      if(typedValue !== "" && typedValue !== this.serializedValue.label){
+    query(typedValue) {
+      if (typedValue !== "" && typedValue !== this.serializedValue.label) {
         // if closed, open it
-        if(!this.isOpen) this.open();
+        if (!this.isOpen) this.open();
       }
     }
   },
   methods: {
-    open(){
+    open() {
       this.isOpen = true;
+      this.$nextTick(() => {
+        this._scrollListToHighlighted();
+      });
     },
-    close(){
-      if(!this.isOpen) return;
-      this.highlightedIndex = 0;
-      this.isOpen = false;
+    close() {
+      if (!this.isOpen) return;
+
+      // if nothing was select, but some keyboard playing occurred, reset to selected index
+      this._updateQuery(this.serializedValue);
+      if(!this.keepOpen) {
+        this.isOpen = false
+      }
     },
-    selectOption(option){
+    selectOption(option) {
       this.query = option.label;
-      this.$emit('select', option)
+      this._setSelectedIndex();
+      this._updateQuery(this.serializedValue);
+      this.$emit("select", option);
+      this.close();
     },
-    selectHighlighted(){
+    selectHighlighted() {
       this.selectOption(this.filteredOptions[this.highlightedIndex]);
-      this.close()
     },
-    reset(){
-      this.query = "";
+    reset() {
       this.highlightedIndex = 0;
-      this.$emit('select', null);
+      this.inputRef.focus();
+      this.selectOption({ label: '', value: null });
     },
     // Keyboard navigation
-    highlight(index){
-      if(this.filteredOptions.length === 0) return;
+    highlight(index) {
+      if (this.filteredOptions.length === 0) return;
 
       this.highlightedIndex = index;
 
       // reaches first scrolls to last
-      if( this.highlightedIndex < 0){
+      if (this.highlightedIndex < 0) {
         this.highlightedIndex = this.filteredOptions.length - 1;
       }
 
       // reaches last goes scrolls to first
-      if( this.highlightedIndex > this.filteredOptions.length - 1 ){
+      if (this.highlightedIndex > this.filteredOptions.length - 1) {
         this.highlightedIndex = 0;
       }
 
       // i don't know a pretty way of doing this but will find out in the future
       // this will break if we use v-if instead of v-show
-      this.optionsScroller.children[this.highlightedIndex].scrollIntoView({block: 'nearest'});
+      this._scrollListToHighlighted();
     },
     highlightPrev() {
       this.highlight(this.highlightedIndex - 1);
@@ -139,84 +174,150 @@ export default {
       this.highlight(this.highlightedIndex + 1);
     },
     handleClickOutside(e) {
+      if (this.keepOpen) this._updateQuery(this.serializedValue);
       if (!this.isOpen) return;
 
       if (!this.$el.contains(e.target)) {
-        this.close()
+        this.close();
       }
     },
-    _validateFormat(obj){
-      if(
-        obj.hasOwnProperty("label") &&
-        obj.hasOwnProperty("value")
-      ) {
-        return true
+    _validateFormat(obj) {
+      if (obj.hasOwnProperty("label") && obj.hasOwnProperty("value")) {
+        return true;
       } else {
-        false
+        false;
+      }
+    },
+
+    /**
+     * for both initial loading (value watch)
+     * and onClose to check if the user just randomly searching terms
+     * But then cancelled and we reset query val to the current selected option (this.value)
+     *
+     * TODO: this serialization checks fill dirty. enhance
+     */
+    _updateQuery(value) {
+      if (!value || (value && value.label === null)) {
+        this.query = "";
+      } else {
+        this.query = value.label;
+      }
+      this.$nextTick(() => {
+        this._scrollListToHighlighted('instant');
+      })
+    },
+
+    /**
+     * Pleas make this human readable
+     */
+    _setSelectedIndex() {
+      let i = this.filteredOptions
+        .map(o => o.label)
+        .indexOf(this.serializedValue.label);
+      let _i = i < 0 ? 0 : i;
+      this.highlightedIndex = _i;
+      this.selectedIndex = i < 0 ? null : _i;
+    },
+
+    // [noteperf] check if ele is scrollable before trigger
+    _scrollListToHighlighted(behavior = 'instant') {
+      if (this.listboxRef) {
+        let target = this.listboxRef.children[this.highlightedIndex];
+        target &&
+          SUPPORTS_SCROLLBEHAVIOR
+            ? target.scrollIntoView({ block: "nearest", behavior})
+            : target.scrollIntoView()
+      }
+    },
+    // dangerous
+    _getFakeRefs() {
+      this.inputRef = this.$el.querySelector(`[${ATTRS_NAMESPACE}=input]`);
+      this.listboxRef = this.$el.querySelector(`[${ATTRS_NAMESPACE}=listbox]`);
+      if (!this.listboxRef) {
+        console.warn(
+          'For accessibility purposes make sure you v-bind="listboxProps to your role="listbox" element aka the list that scrolls throught he options'
+        );
       }
     }
   },
-  created(){
+  created() {
     // look if a selected option is already passed to v-model
     // if not null
-    if(this.value){
+    if (this.value) {
       this.selectOption(this.serializedValue);
     }
   },
-  mounted(){
-    this.optionsScroller = this.$el.querySelector('[data-vue-select-scroller]');
-    document.addEventListener('click', this.handleClickOutside);
+  updated() {
+    this.$emit("updated");
+  },
+  mounted() {
+    this._getFakeRefs();
+    this._scrollListToHighlighted();
+    document.addEventListener("click", this.handleClickOutside);
   },
   beforeDestroy() {
-    document.removeEventListener('click', this.handleClickOutside);
+    document.removeEventListener("click", this.handleClickOutside);
   },
-  render(){
+  render() {
     return this.$scopedSlots.default({
       state: {
         isOpen: this.isOpen,
         highlightedIndex: this.highlightedIndex,
+        selectedIndex: this.selectedIndex
       },
       options: this.filteredOptions,
-      optionEvents: (option) => ({
+      optionEvents: option => ({
         click: () => {
           this.selectOption(option);
+          this.inputRef.focus();
           this.close();
         }
       }),
       inputProps: {
-        value: this.query
+        value: this.query,
+        // this is kind of hack but, don't know a better way yet
+        [`${ATTRS_NAMESPACE}`]: "input"
       },
       inputEvents: {
         click: this.open,
-        input: (e) => this.query = e.target.value,
-        keydown: (e) => {
-          if(e.key === 'ArrowDown'){
-            this.highlightNext()
+        input: e => (this.query = e.target.value),
+        keydown: e => {
+          if (e.key === "ArrowDown") {
+            if (!this.isOpen) {
+              this.open();
+            } else {
+              this.highlightNext();
+            }
           }
-          if(e.key === 'ArrowUp') {
-            this.highlightPrev()
+          if (e.key === "ArrowUp") {
+            this.highlightPrev();
           }
 
-          if(e.key === "Escape" || e.key === "Tab") {
-            this.close()
+          if (e.key === "Escape" || e.key === "Tab") {
+            // do not close other components that might be listening for the escape key
+            if (this.isOpen) e.stopPropagation();
+            this._updateQuery(this.serializedValue);
+            this.close();
           }
 
-          if( e.key === "Enter") {
+          if (e.key === "Enter") {
             e.preventDefault();
 
-            if( this.isOpen && this.filteredOptions.length){
+            if (this.isOpen && this.filteredOptions.length) {
               this.selectHighlighted();
-            } else {
-              this.open()
             }
           }
         }
       },
       actions: {
         reset: () => this.reset(),
-        toggleOptions: () => this.isOpen ? this.close() : this.open()
+        toggleOptions: () =>
+          this.isOpen ? this.close() : (this.open(), this.inputRef.focus())
+      },
+      listboxProps: {
+        [`${ATTRS_NAMESPACE}`]: "listbox"
       }
-    })
+    });
   }
-}
+};
 </script>
\ No newline at end of file
diff --git a/src/index.js b/src/index.js
index 087d019..5ab9d85 100644
--- a/src/index.js
+++ b/src/index.js
@@ -18,4 +18,5 @@ var Plugin = {
 	}
 }
 
+export { RenderlessVueSelect }
 export default Plugin;