diff --git a/gui/src/components/api.js b/gui/src/components/api.js
index e8fc61e04d1abeb9946b315aee704db1d72de069..ee56cd4d732260a9f24e9d7ee94d3e6dbdbd256c 100644
--- a/gui/src/components/api.js
+++ b/gui/src/components/api.js
@@ -474,13 +474,14 @@ class Api {
       .finally(this.onFinishLoading)
   }
 
-  async quantity_search(quantity, search, size, noLoadingIndicator) {
+  async suggestions_search(quantity, search, include, size, noLoadingIndicator) {
     if (!noLoadingIndicator) {
       this.onStartLoading()
     }
     return this.swagger()
-      .then(client => client.apis.repo.quantity_search({
+      .then(client => client.apis.repo.suggestions_search({
         size: size || 20,
+        include: include,
         quantity: quantity,
         ...search
       }))
diff --git a/gui/src/components/search/SearchBarNew.js b/gui/src/components/search/SearchBarNew.js
index 07cbf51661bcca8434242ab909499dbe644cebd6..d6c8055a1673ab6a670fd5f6e13ec6b0203dfe0c 100644
--- a/gui/src/components/search/SearchBarNew.js
+++ b/gui/src/components/search/SearchBarNew.js
@@ -1,4 +1,4 @@
-import React from 'react'
+import React, { useRef, useState, useContext, useCallback, useMemo } from 'react'
 import {searchContext} from './SearchContext'
 import Autocomplete from '@material-ui/lab/Autocomplete'
 import TextField from '@material-ui/core/TextField'
@@ -6,15 +6,21 @@ import { CircularProgress } from '@material-ui/core'
 import * as searchQuantities from '../../searchQuantities.json'
 import { apiContext } from '../api'
 
-const defaultOptions = Object.keys(searchQuantities).map(quantity => searchQuantities[quantity].name)
-
 export default function SearchBar() {
-  const [open, setOpen] = React.useState(false)
-  const [options, setOptions] = React.useState(defaultOptions)
-  const [loading, setLoading] = React.useState(false)
-  const [inputValue, setInputValue] = React.useState('')
-  const {response: {statistics, pagination}, domain, query, setQuery} = React.useContext(searchContext)
-  const {api} = React.useContext(apiContext)
+  const suggestionsTimerRef = useRef(null)
+  const {response: {statistics, pagination}, domain, query, setQuery} = useContext(searchContext)
+  const defaultOptions = useMemo(() => {
+    return Object.keys(searchQuantities)
+      .map(quantity => searchQuantities[quantity].name)
+      .filter(quantity => !quantity.includes('.') || quantity.startsWith(domain.key + '.'))
+  }, [domain.key])
+
+  const [open, setOpen] = useState(false)
+  const [options, setOptions] = useState(defaultOptions)
+  const [loading, setLoading] = useState(false)
+  const [inputValue, setInputValue] = useState('')
+
+  const {api} = useContext(apiContext)
 
   const autocompleteValue = Object.keys(query).map(quantity => `${quantity}=${query[quantity]}`)
 
@@ -33,36 +39,52 @@ export default function SearchBar() {
     }
   }
 
-  const loadValues = (quantity, value) => {
-    setLoading(true)
-    const size = searchQuantities[quantity].statistic_size || 20
-    api.quantity_search(quantity, query, size, true)
-      .then(response => {
-        setLoading(false)
-        const options = Object.keys(response.quantity.values).map(value => `${quantity}=${value}`)
-        setOptions(options)
-        setOpen(true)
-      })
-      .catch(() => {
-        setLoading(false)
-      })
-  }
+  const filterOptions = useCallback((options, params) => {
+    const [quantity, value] = params.inputValue.split('=')
+    const filteredOptions = options.filter(option => {
+      const [optionQuantity, optionValue] = option.split('=')
+      if (!value) {
+        return optionQuantity.includes(quantity) || optionQuantity === quantity
+      } else {
+        return optionValue.includes(value) || optionValue === value
+      }
+    })
+    return filteredOptions
+  }, [])
 
-  const handleInputChange = (event, value, reason) => {
+  const loadOptions = useCallback((quantity, value) => {
+    if (suggestionsTimerRef.current !== null) {
+      clearTimeout(suggestionsTimerRef.current)
+    }
+    suggestionsTimerRef.current = setTimeout(() => {
+      setLoading(true)
+      api.suggestions_search(quantity, query, value, 20, true)
+        .then(response => {
+          setLoading(false)
+          const options = response.suggestions.map(value => `${quantity}=${value}`)
+          setOptions(options)
+          setOpen(true)
+        })
+        .catch(() => {
+          setLoading(false)
+        })
+    }, 200)
+  }, [api, suggestionsTimerRef])
+
+  const handleInputChange = useCallback((event, value, reason) => {
     if (reason === 'input') {
       setInputValue(value)
       const [quantity, quantityValue] = value.split('=')
-      if (!quantityValue) {
-        if (searchQuantities[quantity]) {
-          loadValues(quantity, quantityValue)
-        } else {
-          setOptions(defaultOptions)
-        }
+
+      if (searchQuantities[quantity]) {
+        loadOptions(quantity, quantityValue)
+      } else {
+        setOptions(defaultOptions)
       }
     }
-  }
+  }, [loadOptions])
 
-  const handleChange = (event, entries, reason) => {
+  const handleChange = (event, entries) => {
     const newQuery = entries.reduce((query, entry) => {
       if (entry) {
         const [quantity, value] = entry.split('=')
@@ -91,7 +113,7 @@ export default function SearchBar() {
         setInputValue('')
       } else {
         setInputValue(`${entry}=`)
-        loadValues(quantity)
+        loadOptions(quantity)
       }
     }
   }
@@ -119,9 +141,9 @@ export default function SearchBar() {
     onChange={handleChange}
     onInputChange={handleInputChange}
     getOptionSelected={(option, value) => option === value}
-    getOptionLabel={(option) => option}
     options={options}
     loading={loading}
+    filterOptions={filterOptions}
     renderInput={(params) => (
       <TextField
         {...params}
diff --git a/nomad/app/api/repo.py b/nomad/app/api/repo.py
index 6b41856a370a7fc1e46aea07aa0476cab428354f..cc18e6cb5b3d159d9fcdfcbdc92483ec3d3f75d2 100644
--- a/nomad/app/api/repo.py
+++ b/nomad/app/api/repo.py
@@ -566,6 +566,8 @@ _repo_quantity_search_request_parser.add_argument(
     'after', type=str, help='The after value to use for "scrolling".')
 _repo_quantity_search_request_parser.add_argument(
     'size', type=int, help='The max size of the returned values.')
+_repo_quantity_search_request_parser.add_argument(
+    'value', type=str, help='A partial value. Only values that include this will be returned')
 
 _repo_quantity_model = api.model('RepoQuantity', {
     'after': fields.String(description='The after value that can be used to retrieve the next set of values.'),
@@ -631,6 +633,62 @@ class RepoQuantityResource(Resource):
             abort(400, 'Given quantity does not exist: %s' % str(e))
 
 
+_repo_suggestions_search_request_parser = api.parser()
+add_search_parameters(_repo_suggestions_search_request_parser)
+_repo_suggestions_search_request_parser.add_argument(
+    'size', type=int, help='The max size of the returned values.')
+_repo_suggestions_search_request_parser.add_argument(
+    'include', type=str, help='A substring that all values need to include.')
+
+_repo_suggestions_model = api.model('RepoSuggestionsValues', {
+    'suggestions': fields.List(fields.String, description='A list with the suggested values.')
+})
+
+
+@ns.route('/suggestions/<string:quantity>')
+class RepoSuggestionsResource(Resource):
+    @api.doc('suggestions_search')
+    @api.response(400, 'Invalid requests, e.g. wrong owner type, bad quantity, bad search parameters')
+    @api.expect(_repo_suggestions_search_request_parser, validate=True)
+    @api.marshal_with(_repo_suggestions_model, skip_none=True, code=200, description='Suggestions send')
+    @authenticate()
+    def get(self, quantity: str):
+        '''
+        Retrieve the top values for the given quantity from entries matching the search.
+        Values can be filtered by to include a given value.
+
+        There is no ordering, no pagination, and no scroll interface.
+
+        The result will contain a 'suggestions' key with values. There will be upto 'size' many values.
+        '''
+
+        search_request = search.SearchRequest()
+        args = {
+            key: value
+            for key, value in _repo_suggestions_search_request_parser.parse_args().items()
+            if value is not None}
+
+        apply_search_parameters(search_request, args)
+        size = args.get('size', 20)
+        include = args.get('include', None)
+
+        try:
+            assert size >= 0
+        except AssertionError:
+            abort(400, message='invalid size')
+
+        try:
+            search_request.statistic(quantity, size=size, include=include)
+            results = search_request.execute()
+            results['suggestions'] = list(results['statistics'][quantity].keys())
+
+            return results, 200
+        except KeyError as e:
+            import traceback
+            traceback.print_exc()
+            abort(400, 'Given quantity does not exist: %s' % str(e))
+
+
 _repo_quantities_search_request_parser = api.parser()
 add_search_parameters(_repo_quantities_search_request_parser)
 _repo_quantities_search_request_parser.add_argument(
diff --git a/nomad/search.py b/nomad/search.py
index 7b1499c606c527a9515d7a30680779a60e76ad96..51c827ae18b06c7c7798cc3d610d7ea465e3917e 100644
--- a/nomad/search.py
+++ b/nomad/search.py
@@ -297,7 +297,7 @@ class SearchRequest:
 
     def statistic(
             self, quantity_name: str, size: int, metrics_to_use: List[str] = [],
-            order: Dict[str, str] = dict(_key='asc')):
+            order: Dict[str, str] = dict(_key='asc'), include: str = None):
         '''
         This can be used to display statistics over the searched entries and allows to
         implement faceted search on the top values for each quantity.
@@ -322,9 +322,15 @@ class SearchRequest:
                 ``unique_code_runs``, ``datasets``, other domain specific metrics.
                 The basic doc_count metric ``code_runs`` is always given.
             order: The order dictionary is passed to the elastic search aggregation.
+            include:
+                Uses an regular expression in ES to only return values that include
+                the given substring.
         '''
         quantity = search_quantities[quantity_name]
-        terms = A('terms', field=quantity.search_field, size=size, order=order)
+        terms_kwargs = {}
+        if include is not None:
+            terms_kwargs['include'] = '.*%s.*' % include
+        terms = A('terms', field=quantity.search_field, size=size, order=order, **terms_kwargs)
 
         buckets = self._search.aggs.bucket('statistics:%s' % quantity_name, terms)
         self._add_metrics(buckets, metrics_to_use)
diff --git a/tests/app/test_api.py b/tests/app/test_api.py
index 018b982a86761b228b3360833565332a99a1cebc..51b9a4cb4ab0f62b086eaacd3ca727f004649fb6 100644
--- a/tests/app/test_api.py
+++ b/tests/app/test_api.py
@@ -1048,6 +1048,23 @@ class TestRepo():
         rv = api.get('/repo/?owner=user')
         assert rv.status_code == 401
 
+    @pytest.mark.parametrize('suggestions, quantity, value', [
+        (1, 'dft.system', 'bulk'),
+        (1, 'dft.system', 'ulk'),
+        (1, 'dft.system', 'ul'),
+        (0, 'dft.system', 'notbulk'),
+        (1, 'dft.system', None)
+    ])
+    def test_suggestions_search(self, api, example_elastic_calcs, no_warn, test_user_auth, suggestions, quantity, value):
+        url = '/repo/suggestions/%s' % quantity
+        if value is not None:
+            url = url + '?include=%s' % value
+        rv = api.get(url, headers=test_user_auth)
+        assert rv.status_code == 200
+        data = json.loads(rv.data)
+        values = data['suggestions']
+        assert len(values) == suggestions
+
     @pytest.mark.parametrize('calcs, quantity, value', [
         (2, 'dft.system', 'bulk'),
         (0, 'dft.system', 'atom'),
diff --git a/tests/test_search.py b/tests/test_search.py
index 82d50ce091ef5c46aa133896dff76dd90bbfebf0..40ed5a9716039532e51c8de717f2d3f0a8f1b0e7 100644
--- a/tests/test_search.py
+++ b/tests/test_search.py
@@ -170,6 +170,14 @@ def test_search_statistics(elastic, example_search_data):
     assert 'quantities' not in results
 
 
+def test_suggest_statistics(elastic, example_search_data):
+    results = SearchRequest(domain='dft').statistic('dft.system', include='ulk', size=2).execute()
+    assert len(results['statistics']['dft.system']) == 1
+
+    results = SearchRequest(domain='dft').statistic('dft.system', include='not_ulk', size=2).execute()
+    assert len(results['statistics']['dft.system']) == 0
+
+
 def test_search_totals(elastic, example_search_data):
     use_metrics = search_extension.metrics.keys()