From e32230ac0a09d14de6330be6c0de131d328e8f16 Mon Sep 17 00:00:00 2001
From: Lauri Himanen <lauri.himanen@gmail.com>
Date: Mon, 21 Oct 2024 06:02:46 +0000
Subject: [PATCH] Added the possibility for defining the menu structure and
 contents through apps.

Changelog: Added
---
 docs/howto/plugins/apps.md                    |  121 +-
 .../src/nomad_countries/apps/__init__.py      |   12 +-
 examples/data/rdm_tutorial/tutorial.ipynb     |    4 -
 gui/src/components/UserdataPage.js            |    4 +-
 gui/src/components/UserdataPage.spec.js       |    6 +-
 gui/src/components/dataset/DatasetPage.js     |    4 +-
 .../editQuantity/QueryEditQuantity.js         |    2 +-
 .../entry/properties/SampleHistoryCard.js     |    2 +-
 gui/src/components/nav/Routes.js              |    4 +-
 gui/src/components/plotting/PlotHistogram.js  |   13 +-
 gui/src/components/plotting/PlotScatter.js    |   19 +-
 gui/src/components/plotting/common.js         |   28 +-
 gui/src/components/search/Filter.js           |   24 +-
 gui/src/components/search/FilterRegistry.js   |  327 +-
 .../components/search/FilterRegistry.spec.js  |    8 +-
 gui/src/components/search/FilterTitle.js      |   28 +-
 gui/src/components/search/Query.spec.js       |    2 +-
 gui/src/components/search/SearchBar.spec.js   |    8 +-
 gui/src/components/search/SearchContext.js    |   54 +-
 .../components/search/SearchContext.spec.js   |    2 +-
 gui/src/components/search/SearchMenu.js       |  287 +
 gui/src/components/search/SearchMenu.spec.js  |  100 +
 gui/src/components/search/SearchPage.js       |   23 +-
 gui/src/components/search/SearchPage.spec.js  |   58 +-
 .../components/search/SearchResults.spec.js   |    2 +-
 gui/src/components/search/conftest.spec.js    |   93 +-
 .../components/search/input/InputCheckbox.js  |  156 -
 .../InputCustomQuantities.js}                 |  137 +-
 .../InputDefinitions.js}                      |  108 +-
 .../search/input/InputField.spec.js           |  219 -
 gui/src/components/search/input/InputGrid.js  |   72 +-
 .../components/search/input/InputHeader.js    |    5 +-
 .../{InputRange.js => InputHistogram.js}      |  198 +-
 .../search/input/InputHistogram.spec.js       |  311 +
 .../search/input/InputMetainfo.spec.js        |    4 +-
 .../search/input/InputNestedObject.js         |  102 +
 .../InputOptimade.js}                         |   91 +-
 .../search/input/InputPeriodicTable.js        |   95 +-
 .../search/input/InputPeriodicTable.spec.js   |  141 +-
 .../search/input/InputRange.spec.js           |  203 -
 .../input/{InputField.js => InputTerms.js}    |  241 +-
 .../search/input/InputTerms.spec.js           |  209 +
 .../search/input/InputVisibility.js           |   43 +
 .../components/search/menus/FilterMainMenu.js |  176 -
 gui/src/components/search/menus/FilterMenu.js |  646 --
 .../components/search/menus/FilterSettings.js |   80 -
 .../search/menus/FilterSubMenuAuthor.js       |   75 -
 .../search/menus/FilterSubMenuBSE.js          |   88 -
 .../menus/FilterSubMenuCatalystProperties.js  |  124 -
 .../search/menus/FilterSubMenuDFT.js          |   93 -
 .../search/menus/FilterSubMenuDMFT.js         |   97 -
 .../search/menus/FilterSubMenuEELS.js         |   75 -
 .../search/menus/FilterSubMenuELN.js          |  105 -
 .../search/menus/FilterSubMenuElectronic.js   |   89 -
 .../search/menus/FilterSubMenuElements.js     |   96 -
 .../search/menus/FilterSubMenuGW.js           |   72 -
 .../FilterSubMenuGeometryOptimization.js      |   69 -
 .../search/menus/FilterSubMenuMaterial.js     |   47 -
 .../search/menus/FilterSubMenuMechanical.js   |   93 -
 .../search/menus/FilterSubMenuMethod.js       |   53 -
 .../menus/FilterSubMenuMolecularDynamics.js   |   65 -
 .../search/menus/FilterSubMenuPrecision.js    |   81 -
 .../search/menus/FilterSubMenuSolarCell.js    |   99 -
 .../search/menus/FilterSubMenuStructure.js    |  104 -
 .../search/menus/FilterSubMenuTB.js           |   64 -
 .../search/menus/FilterSubMenuVibrational.js  |   47 -
 gui/src/components/search/menus/Menu.js       |  489 ++
 .../components/search/widgets/Dashboard.js    |   20 +-
 .../search/widgets/Dashboard.spec.js          |   24 +-
 gui/src/components/search/widgets/Widget.js   |    4 +-
 .../components/search/widgets/WidgetGrid.js   |    6 +-
 .../components/search/widgets/WidgetHeader.js |    1 +
 .../search/widgets/WidgetHistogram.js         |   35 +-
 .../search/widgets/WidgetHistogram.spec.js    |   61 +
 .../search/widgets/WidgetHistogramEdit.js     |   32 +-
 .../widgets/WidgetHistogramEdit.spec.js       |    6 +-
 .../search/widgets/WidgetPeriodicTable.js     |   30 +-
 .../search/widgets/WidgetScatterPlot.js       |   79 +-
 .../search/widgets/WidgetScatterPlot.spec.js  |   52 +-
 .../search/widgets/WidgetScatterPlotEdit.js   |   80 +-
 .../widgets/WidgetScatterPlotEdit.spec.js     |   34 +-
 .../components/search/widgets/WidgetTerms.js  |   46 +-
 .../search/widgets/WidgetTerms.spec.js        |    4 +-
 .../components/uploads/SectionSelectDialog.js |   21 +-
 .../components/uploads/UploadSearchMenu.js    |    5 +-
 gui/src/utils.js                              |   22 +-
 gui/tests/artifacts.js                        |    8 +-
 gui/tests/env.js                              | 7037 +++++++++++++++--
 nomad/config/defaults.yaml                    |    9 +-
 nomad/config/models/ui.py                     | 1302 ++-
 nomad/datamodel/results.py                    |    2 +-
 91 files changed, 10516 insertions(+), 5001 deletions(-)
 create mode 100644 gui/src/components/search/SearchMenu.js
 create mode 100644 gui/src/components/search/SearchMenu.spec.js
 delete mode 100644 gui/src/components/search/input/InputCheckbox.js
 rename gui/src/components/search/{menus/FilterSubMenuCustomQuantities.js => input/InputCustomQuantities.js} (82%)
 rename gui/src/components/search/{menus/FilterSubMenuMetadata.js => input/InputDefinitions.js} (62%)
 delete mode 100644 gui/src/components/search/input/InputField.spec.js
 rename gui/src/components/search/input/{InputRange.js => InputHistogram.js} (83%)
 create mode 100644 gui/src/components/search/input/InputHistogram.spec.js
 create mode 100644 gui/src/components/search/input/InputNestedObject.js
 rename gui/src/components/search/{menus/FilterSubMenuOptimade.js => input/InputOptimade.js} (80%)
 delete mode 100644 gui/src/components/search/input/InputRange.spec.js
 rename gui/src/components/search/input/{InputField.js => InputTerms.js} (61%)
 create mode 100644 gui/src/components/search/input/InputTerms.spec.js
 create mode 100644 gui/src/components/search/input/InputVisibility.js
 delete mode 100644 gui/src/components/search/menus/FilterMainMenu.js
 delete mode 100644 gui/src/components/search/menus/FilterMenu.js
 delete mode 100644 gui/src/components/search/menus/FilterSettings.js
 delete mode 100644 gui/src/components/search/menus/FilterSubMenuAuthor.js
 delete mode 100644 gui/src/components/search/menus/FilterSubMenuBSE.js
 delete mode 100755 gui/src/components/search/menus/FilterSubMenuCatalystProperties.js
 delete mode 100644 gui/src/components/search/menus/FilterSubMenuDFT.js
 delete mode 100644 gui/src/components/search/menus/FilterSubMenuDMFT.js
 delete mode 100644 gui/src/components/search/menus/FilterSubMenuEELS.js
 delete mode 100644 gui/src/components/search/menus/FilterSubMenuELN.js
 delete mode 100644 gui/src/components/search/menus/FilterSubMenuElectronic.js
 delete mode 100644 gui/src/components/search/menus/FilterSubMenuElements.js
 delete mode 100644 gui/src/components/search/menus/FilterSubMenuGW.js
 delete mode 100644 gui/src/components/search/menus/FilterSubMenuGeometryOptimization.js
 delete mode 100644 gui/src/components/search/menus/FilterSubMenuMaterial.js
 delete mode 100644 gui/src/components/search/menus/FilterSubMenuMechanical.js
 delete mode 100644 gui/src/components/search/menus/FilterSubMenuMethod.js
 delete mode 100644 gui/src/components/search/menus/FilterSubMenuMolecularDynamics.js
 delete mode 100644 gui/src/components/search/menus/FilterSubMenuPrecision.js
 delete mode 100644 gui/src/components/search/menus/FilterSubMenuSolarCell.js
 delete mode 100644 gui/src/components/search/menus/FilterSubMenuStructure.js
 delete mode 100644 gui/src/components/search/menus/FilterSubMenuTB.js
 delete mode 100644 gui/src/components/search/menus/FilterSubMenuVibrational.js
 create mode 100644 gui/src/components/search/menus/Menu.js
 create mode 100644 gui/src/components/search/widgets/WidgetHistogram.spec.js

diff --git a/docs/howto/plugins/apps.md b/docs/howto/plugins/apps.md
index 68bba66282..ad85e77a5a 100644
--- a/docs/howto/plugins/apps.md
+++ b/docs/howto/plugins/apps.md
@@ -46,13 +46,13 @@ The entry point instance should then be added to the `[project.entry-points.'nom
 myapp = "nomad_example.apps:myapp"
 ```
 
-## `App` class
+## Creating an `App`
 
 The definition fo the actual app is given as an instance of the `App` class specified as part of the entry point. A full breakdown of the model is given below in the [app reference](#app-reference), but here is a small example:
 
 ```python
 from nomad.config.models.plugins import AppEntryPoint
-from nomad.config.models.ui import App, Column, FilterMenu, FilterMenus, Filters
+from nomad.config.models.ui import App, Column, Menu, MenuItemPeriodicTable, MenuItemHistogram, MenuItemTerms, SearchQuantities
 
 schema = 'nomad_example.schema_packages.mypackage.MySchema'
 myapp = AppEntryPoint(
@@ -69,12 +69,12 @@ myapp = AppEntryPoint(
         description='An app customized for me.',
         # Longer description that can also use markdown
         readme='Here is a much longer description of this app.',
-        # Controls the available search filters. If you want to filter by
-        # quantities in a schema package, you need to load the schema package
-        # explicitly here. Note that you can use a glob syntax to load the
-        # entire package, or just a single schema from a package.
-        filters=Filters(
-            include=[f'*#{schema}'],
+        # If you want to use quantities from a custom schema, you need to load
+        # the search quantities from it first here. Note that you can use a glob
+        # syntax to load the entire package, or just a single schema from a
+        # package.
+        search_quantities=SearchQuantities(
+            include=['*#nomad_example.schema_packages.mypackage.MySchema'],
         ),
         # Controls which columns are shown in the results table
         columns=[
@@ -97,18 +97,39 @@ myapp = AppEntryPoint(
         filters_locked={
             "section_defs.definition_qualified_name:all": [schema]
         },
-        # Controls the filter menus shown on the left
-        filter_menus=FilterMenus(
-            options={
-                'material': FilterMenu(label="Material"),
-            }
-        ),
+        # Controls the menu shown on the left
+        menu = Menu(
+            title='Material',
+            items=[
+                Menu(
+                    title='elements',
+                    items=[
+                        MenuItemPeriodicTable(
+                            quantity='results.material.elements',
+                        ),
+                        MenuItemTerms(
+                            quantity='results.material.chemical_formula_hill',
+                            width=6,
+                            options=0,
+                        ),
+                        MenuItemTerms(
+                            quantity='results.material.chemical_formula_iupac',
+                            width=6,
+                            options=0,
+                        ),
+                        MenuItemHistogram(
+                            x='results.material.n_elements',
+                        )
+                    ]
+                )
+            ]
+        )
         # Controls the default dashboard shown in the search interface
         dashboard={
             'widgets': [
                 {
                     'type': 'histogram',
-                    'showinput': False,
+                    'show_input': False,
                     'autorange': True,
                     'nbins': 30,
                     'scale': 'linear',
@@ -151,19 +172,15 @@ myapp = AppEntryPoint(
         )
     ```
 
-### Loading custom quantity definitions into an app
+### Loading quantity definitions into an app
 
-By default, none of the quantities from custom schemas are available in an app, and they need to be explicitly added. Each app may define additional **filters** that should be enabled in it. Filters have a special meaning in the app context: filters are pieces of (meta)info that can be queried in the search interface of the app, but also targeted in the rest of the app configuration as explained below in.
+By default, quantities from custom schemas are not available in an app, and they need to be explicitly added. Each app may define the quantities to load by using the **search_quantities** field in the app config. Once loaded, these search quantities can be queried in the search interface, but also targeted in the rest of the app configuration as explained below.
 
-!!! note
+!!! important
 
-    Note that not all of the quantities from a custom schema can be exposed as
-    filters. At the moment we only support targeting **scalar** quantities from
-    custom schemas.
+    Note that not all of the quantities from a custom schema can be loaded into the search. At the moment we only support loading **scalar** quantities from custom schemas.
 
-Each schema has a unique name within the NOMAD ecosystem, which is needed to
-target them in the configuration. The name depends on the resource in which the
-schema is defined in:
+Each schema has a unique name within the NOMAD ecosystem, which is needed to target them in the configuration. The name depends on the resource in which the schema is defined in:
 
 - Python schemas are identified by the python path for the class that inherits
 from `Schema`. For example, if you have a python package called `nomad_example`,
@@ -182,7 +199,7 @@ include all filters from the Python schema defined in the class
 `nomad_example.schema_packages.mypackage.MySchema`, you could use:
 
 ```python
-filters=Filters(
+search_quantities=SearchQuantities(
     include=['*#nomad_example.schema_packages.mypackage.MySchema']
 )
 ```
@@ -190,12 +207,12 @@ filters=Filters(
 The same thing for a YAML schema could be achieved with:
 
 ```python
-filters=Filters(
+search_quantities=SearchQuantities(
     include=['*#entry_id:<entry_id>.MySchema']
 )
 ```
 
-Once quantities from a schema are included in an app as filters, they can be targeted in the rest of the app. The app configuration often refers to specific filters to configure parts of the user interface. For example, one could configure the results table to show a new column using one of the schema quantities with:
+Once search quantities are loaded, they can be targeted in the rest of the app. The app configuration often refers to specific search quantities to configure parts of the user interface. For example, one could configure the results table to show a new column using one of the search quantities with:
 
 ```python
 columns=[
@@ -217,6 +234,56 @@ by a hashtag (#), for example `data.mysection.myquantity#entry_id:<entry_id>.MyS
 - Quantities that are common for all NOMAD entries can be targeted by using only
 the path without the need for specifying a schema, e.g. `results.material.symmetry.space_group`.
 
+### Menu
+
+The `menu` field controls the structure of the menu shown on the left side of the search interface. Menus have a controllable width, and they contains items that are displayed on a 12-based grid. You can also nest menus within each other. For example, this defines a menu with two levels:
+
+```python
+# This is a top level menu that is always visible. It shows two items: a terms
+# item and a submenu beneath it.
+menu = Menu(
+    size='sm',
+    items=[
+        MenuItemTerms(
+            search_quantity='authors.name',
+            options=5
+        ),
+        # This is a submenu whose items become visible once selected. It
+        # contains three items: one full-width histogram and two terms items
+        # which are displayed side-by-side.
+        Menu(
+            title='Submenu'
+            size='md',
+            items=[
+                MenuItemHistogram(
+                    search_quantity='upload_create_time'
+                ),
+                # These items target data from a custom schema
+                MenuItemTerms(
+                    width=6,
+                    search_quantity='data.quantity1#nomad_example.schema_packages.mypackage.MySchema'
+                ),
+                MenuItemTerms(
+                    width=6,
+                    search_quantity='data.quantity2#nomad_example.schema_packages.mypackage.MySchema'
+                )
+            ]
+        )
+    ]
+)
+```
+
+The following items are supported in menus, and you can read more about them in the App reference:
+
+ - [`Menu`](#menu_1): Defines a nested submenu.
+ - [`MenuItemTerms`](#menuitemterms): Used to display a set of possible text options.
+ - [`MenuItemHistogram`](#menuitemhistogram): Histogram of numerical values.
+ - [`MenuItemPeriodictable`](#menuitemperiodictable): Displays a periodic table.
+ - [`MenuItemOptimade`](#menuitemoptimade): OPTIMADE query field.
+ - [`MenuItemVisibility`](#menuitemvisibility): Controls for the query visibility.
+ - [`MenuItemDefinitions`](#menuitemdefinitions): Shows a tree of available definitions from which items can be selected for the query.
+ - [`MenuItemCustomQuantities`](#menuitemcustomquantities): Form for querying custom quantities coming from any schema.
+ - [`MenuItemNestedObject`](#menuitemnestedobject): Used to group together menu items so that their query is performed using an Elasticsearch nested query. Note that you cannot yet use nested queries for search quantities originating from custom schemas.
 
 ## App reference
 
diff --git a/examples/data/cow_tutorial/nomad-countries/src/nomad_countries/apps/__init__.py b/examples/data/cow_tutorial/nomad-countries/src/nomad_countries/apps/__init__.py
index 8ed73adc29..45376d3fd0 100644
--- a/examples/data/cow_tutorial/nomad-countries/src/nomad_countries/apps/__init__.py
+++ b/examples/data/cow_tutorial/nomad-countries/src/nomad_countries/apps/__init__.py
@@ -38,7 +38,6 @@ country = AppEntryPoint(
         dashboard=Dashboard(
             widgets=[
                 WidgetScatterPlot(
-                    type='scatterplot',
                     layout={'lg': Layout(h=6, w=8, x=0, y=0)},
                     x=Axis(quantity=f'data.literacy#{schema}'),
                     y=Axis(quantity=f'data.industry#{schema}'),
@@ -46,7 +45,6 @@ country = AppEntryPoint(
                     autorange=True,
                 ),
                 WidgetScatterPlot(
-                    type='scatterplot',
                     layout={'lg': Layout(h=6, w=8, x=8, y=0)},
                     x=Axis(quantity=f'data.literacy#{schema}'),
                     y=Axis(quantity=f'data.agriculture#{schema}'),
@@ -54,7 +52,6 @@ country = AppEntryPoint(
                     autorange=True,
                 ),
                 WidgetScatterPlot(
-                    type='scatterplot',
                     layout={'lg': Layout(h=6, w=8, x=16, y=0)},
                     x=Axis(quantity=f'data.literacy#{schema}'),
                     y=Axis(quantity=f'data.service#{schema}'),
@@ -62,30 +59,27 @@ country = AppEntryPoint(
                     autorange=True,
                 ),
                 WidgetHistogram(
-                    type='histogram',
                     layout={'lg': Layout(h=3, w=8, x=0, y=6)},
                     quantity=f'data.phones#{schema}',
                     scale='1/2',
                     nbins=30,
-                    showinput=False,
+                    show_input=False,
                     autorange=True,
                 ),
                 WidgetHistogram(
-                    type='histogram',
                     layout={'lg': Layout(h=3, w=8, x=8, y=6)},
                     quantity=f'data.birthrate#{schema}',
                     scale='linear',
                     nbins=30,
-                    showinput=False,
+                    show_input=False,
                     autorange=True,
                 ),
                 WidgetHistogram(
-                    type='histogram',
                     layout={'lg': Layout(h=3, w=8, x=16, y=6)},
                     quantity=f'data.net_migration#{schema}',
                     scale='linear',
                     nbins=30,
-                    showinput=False,
+                    show_input=False,
                     autorange=True,
                 ),
             ]
diff --git a/examples/data/rdm_tutorial/tutorial.ipynb b/examples/data/rdm_tutorial/tutorial.ipynb
index 741ae2e421..08f156e091 100644
--- a/examples/data/rdm_tutorial/tutorial.ipynb
+++ b/examples/data/rdm_tutorial/tutorial.ipynb
@@ -8741,13 +8741,11 @@
     "    dashboard=Dashboard(\n",
     "        widgets=[\n",
     "            WidgetPeriodicTable(\n",
-    "                type='periodictable',\n",
     "                scale='linear',\n",
     "                quantity='results.material.elements',\n",
     "                layout={'lg': Layout(w=11, h=7, x=0, y=0)},\n",
     "            ),\n",
     "            WidgetScatterPlot(\n",
-    "                type='scatterplot',\n",
     "                layout={'lg': Layout(w=7, h=7, x=11, y=0)},\n",
     "                x=Axis(quantity=f'data.peak_emission_wavelength#{schema}', unit='nm'),\n",
     "                y=Axis(quantity=f'data.photoluminescence_quantum_yield#{schema}'),\n",
@@ -8759,7 +8757,6 @@
     "                scale='linear',\n",
     "            ),\n",
     "            WidgetHistogram(\n",
-    "                type='histogram',\n",
     "                layout={'lg': Layout(w=12, h=4, x=12, y=7)},\n",
     "                autorange=False,\n",
     "                nbins=30,\n",
@@ -8767,7 +8764,6 @@
     "                quantity=f'data.delayed_lifetime#{schema}',\n",
     "            ),\n",
     "            WidgetHistogram(\n",
-    "                type='histogram',\n",
     "                layout={'lg': Layout(w=12, h=4, x=12, y=7)},\n",
     "                autorange=False,\n",
     "                nbins=30,\n",
diff --git a/gui/src/components/UserdataPage.js b/gui/src/components/UserdataPage.js
index 2481cfd541..73bc57d998 100644
--- a/gui/src/components/UserdataPage.js
+++ b/gui/src/components/UserdataPage.js
@@ -86,8 +86,8 @@ const UserdataPage = React.memo(() => {
     initialPagination={context?.pagination}
     initialColumns={context?.columns}
     initialRows={context?.rows}
-    initialFilterMenus={context?.filter_menus}
-    initialFilters={context?.filters}
+    initialMenu={context?.menu}
+    initialSearchQuantities={context?.search_quantities}
     initialFiltersLocked={initialFiltersLocked}
     initialDashboard={context?.dashboard}
     initialSearchSyntaxes={context?.search_syntaxes}
diff --git a/gui/src/components/UserdataPage.spec.js b/gui/src/components/UserdataPage.spec.js
index 01e1e6866e..c9e7da93a2 100644
--- a/gui/src/components/UserdataPage.spec.js
+++ b/gui/src/components/UserdataPage.spec.js
@@ -18,7 +18,7 @@
 
 import React from 'react'
 import { render, startAPI, closeAPI } from './conftest.spec'
-import { expectFilterMainMenu, expectSearchResults } from './search/conftest.spec'
+import { expectMenu, expectSearchResults } from './search/conftest.spec'
 import { ui } from '../config'
 import UserDatapage from './UserdataPage'
 import { minutes } from '../setupTests'
@@ -28,7 +28,7 @@ test('renders user data search page correctly', async () => {
   await startAPI('tests.states.search.search', 'tests/data/search/userdatapage', 'test', 'password')
   render(<UserDatapage />)
 
-  await expectFilterMainMenu(context)
-  await expectSearchResults(context)
+  await expectMenu(context.menu)
+  await expectSearchResults(context.columns)
   closeAPI()
 }, 5 * minutes)
diff --git a/gui/src/components/dataset/DatasetPage.js b/gui/src/components/dataset/DatasetPage.js
index dbd81e300e..01f287289e 100644
--- a/gui/src/components/dataset/DatasetPage.js
+++ b/gui/src/components/dataset/DatasetPage.js
@@ -73,8 +73,8 @@ const DatasetPage = React.memo(({match}) => {
       initialPagination={context?.pagination}
       initialColumns={context?.columns}
       initialRows={context?.rows}
-      initialFilterMenus={context?.filter_menus}
-      initialFilters={context?.filters}
+      initialMenu={context?.menu}
+      initialSearchQuantities={context?.search_quantities}
       initialFiltersLocked={datasetFilter}
       initialDashboard={context?.dashboard}
       initialSearchSyntaxes={context?.search_syntaxes}
diff --git a/gui/src/components/editQuantity/QueryEditQuantity.js b/gui/src/components/editQuantity/QueryEditQuantity.js
index 87af053a8e..8417258974 100644
--- a/gui/src/components/editQuantity/QueryEditQuantity.js
+++ b/gui/src/components/editQuantity/QueryEditQuantity.js
@@ -269,7 +269,7 @@ function QueryEditQuantity({quantityDef, onChange, value, storeInArchive, index,
       initialPagination={context?.pagination}
       initialColumns={columns}
       initialRows={rows}
-      initialFilterMenus={context?.filter_menus}
+      initialMenu={context?.menu}
       initialFiltersLocked={undefined}
       initialFilterValues={filters}
       initialSearchSyntaxes={context?.search_syntaxes}
diff --git a/gui/src/components/entry/properties/SampleHistoryCard.js b/gui/src/components/entry/properties/SampleHistoryCard.js
index b5e16ba637..0dc26bbb66 100644
--- a/gui/src/components/entry/properties/SampleHistoryCard.js
+++ b/gui/src/components/entry/properties/SampleHistoryCard.js
@@ -76,7 +76,7 @@ const SampleHistoryUsingCard = memo(({ index }) => {
       initialPagination={context?.pagination}
       initialColumns={context?.columns}
       initialRows={context?.rows}
-      initialFilterMenus={context?.filter_menus}
+      initialMenu={context?.menu}
       initialFiltersLocked={filtersLocked}
       initialSearchSyntaxes={context?.search_syntaxes}
     >
diff --git a/gui/src/components/nav/Routes.js b/gui/src/components/nav/Routes.js
index aef86e2a28..85387fd2be 100644
--- a/gui/src/components/nav/Routes.js
+++ b/gui/src/components/nav/Routes.js
@@ -182,8 +182,8 @@ const searchRoutes = apps
           initialPagination={context.pagination}
           initialColumns={context.columns}
           initialRows={context.rows}
-          initialFilterMenus={context.filter_menus}
-          initialFilters={context?.filters}
+          initialMenu={context.menu}
+          initialSearchQuantities={context?.search_quantities}
           initialFiltersLocked={context.filters_locked}
           initialDashboard={context?.dashboard}
           initialSearchSyntaxes={context?.search_syntaxes}
diff --git a/gui/src/components/plotting/PlotHistogram.js b/gui/src/components/plotting/PlotHistogram.js
index 1414a77e6d..d83861097f 100644
--- a/gui/src/components/plotting/PlotHistogram.js
+++ b/gui/src/components/plotting/PlotHistogram.js
@@ -150,6 +150,9 @@ const useStyles = makeStyles(theme => ({
     flexDirection: 'row',
     justifyContent: 'center',
     alignItems: 'flex-start'
+  },
+  axisTitle: {
+    fontSize: '0.75rem'
   }
 }))
 const PlotHistogram = React.memo(({
@@ -178,7 +181,7 @@ const PlotHistogram = React.memo(({
   maxXInclusive,
   className,
   classes,
-  showinput,
+  showInput,
   minError,
   maxError,
   minInput,
@@ -191,6 +194,7 @@ const PlotHistogram = React.memo(({
   'data-testid': testID
 }) => {
   const styles = useStyles(classes)
+  const titleClasses = {text: styles.axisTitle}
   const useDynamicStyles = makeStyles((theme) => {
     const color = highlight ? theme.palette.secondary.main : theme.palette.primary.main
     return {
@@ -531,11 +535,11 @@ const PlotHistogram = React.memo(({
 
   const titleComp = <div className={styles.title}>
     <FilterTitle
+      variant="subtitle2"
+      classes={titleClasses}
       quantity={xAxis.quantity}
       label={xAxis.title}
       unit={xAxis.unit}
-      variant="caption"
-      className={styles.titletext}
       noWrap={false}
     />
   </div>
@@ -545,7 +549,7 @@ const PlotHistogram = React.memo(({
       {!disableHistogram && <div className={clsx(styles.histogram, classes?.histogram)}>{histComp}</div>}
       {!disableXTitle && titleComp}
       <div className={styles.row}>
-        {showinput
+        {showInput
           ? <>
             {inputMinField}
             {(disableHistogram && !isTime)
@@ -609,7 +613,6 @@ PlotHistogram.propTypes = {
   onMaxChange: PropTypes.func,
   onMinSubmit: PropTypes.func,
   onMaxSubmit: PropTypes.func,
-  showinput: PropTypes.bool,
   maxError: PropTypes.any,
   minError: PropTypes.any,
   maxInput: PropTypes.any,
diff --git a/gui/src/components/plotting/PlotScatter.js b/gui/src/components/plotting/PlotScatter.js
index a74666ef20..d856bf9e2f 100644
--- a/gui/src/components/plotting/PlotScatter.js
+++ b/gui/src/components/plotting/PlotScatter.js
@@ -82,6 +82,9 @@ const useStyles = makeStyles(theme => ({
   },
   colorlabel: {
     transform: 'rotate(90deg)'
+  },
+  axisTitle: {
+    fontSize: '0.75rem'
   }
 }))
 const PlotScatter = React.memo(forwardRef((
@@ -101,6 +104,7 @@ const PlotScatter = React.memo(forwardRef((
 }, canvas) => {
   const styles = useStyles()
   const theme = useTheme()
+  const titleClasses = {text: styles.axisTitle}
   const [finalData, setFinalData] = useState(!data ? data : undefined)
   const history = useHistory()
 
@@ -131,7 +135,7 @@ const PlotScatter = React.memo(forwardRef((
     // If dealing with a quantized color, each group is separated into it's own
     // trace which has a legend as well.
     const traces = []
-    if (colorAxis?.quantity && discrete) {
+    if (colorAxis?.search_quantity && discrete) {
       const options = [...new Set(data.color)]
       const nOptions = options.length
       const scale = d3.scaleSequential([0, 1], d3.interpolateTurbo)
@@ -178,7 +182,7 @@ const PlotScatter = React.memo(forwardRef((
         })
       }
     // When dealing with a continuous color, display a colormap
-    } else if (colorAxis?.quantity && !discrete) {
+    } else if (colorAxis?.search_quantity && !discrete) {
       traces.push({
         x: data.x,
         y: data.y,
@@ -247,7 +251,7 @@ const PlotScatter = React.memo(forwardRef((
       })
     }
     setFinalData(traces)
-  }, [colorAxis?.quantity, colorAxis?.title, colorAxis?.unit, data, discrete, theme, xAxis.title, xAxis.unit, yAxis.title, yAxis.unit])
+  }, [colorAxis?.search_quantity, colorAxis?.title, colorAxis?.unit, data, discrete, theme, xAxis.title, xAxis.unit, yAxis.title, yAxis.unit])
 
   const layout = useMemo(() => {
     return {
@@ -314,10 +318,11 @@ const PlotScatter = React.memo(forwardRef((
   return <div className={styles.root}>
     <div className={styles.yaxis}>
       <FilterTitle
+        variant="subtitle2"
+        classes={titleClasses}
         quantity={yAxis.quantity}
         label={yAxis.title}
         unit={yAxis.unit}
-        variant="caption"
         rotation="up"
       />
     </div>
@@ -340,21 +345,23 @@ const PlotScatter = React.memo(forwardRef((
     <div className={styles.square} />
     <div className={styles.xaxis}>
       <FilterTitle
+        variant="subtitle2"
+        classes={titleClasses}
         quantity={xAxis.quantity}
         label={xAxis.title}
         unit={xAxis.unit}
-        variant="caption"
       />
     </div>
     {!discrete && colorAxis &&
       <div className={styles.color}>
         <FilterTitle
+          variant="subtitle2"
+          classes={titleClasses}
           rotation="down"
           quantity={colorAxis.quantity}
           unit={colorAxis.unit}
           label={colorAxis.title}
           description=""
-          variant="caption"
         />
       </div>
     }
diff --git a/gui/src/components/plotting/common.js b/gui/src/components/plotting/common.js
index e9c3086e5f..559fc3f859 100644
--- a/gui/src/components/plotting/common.js
+++ b/gui/src/components/plotting/common.js
@@ -39,7 +39,8 @@ import {
   eachQuarterOfInterval
 } from 'date-fns'
 import { scale as chromaScale } from 'chroma-js'
-import { scale as scaleUtils, add, DType, formatNumber } from '../../utils.js'
+import { scale as scaleUtils, add, DType, formatNumber, getDisplayLabel, parseJMESPath } from '../../utils.js'
+import { Unit } from '../units/Unit'
 
 export const scales = {
   'linear': 'linear',
@@ -485,3 +486,28 @@ export function getPlotTracesVertical(plots, theme) {
   }
   return size(traces) ? traces : undefined
 }
+
+/**
+ * Returns a fully configured axis object for plotting.
+ *
+ * @param {object} axis The original axis configuration.
+ * @param {object} filterData Filters registered in the current search context.
+ * @param {object} units Units in current unit system.
+ */
+export function getAxisConfig(axis, filterData, units) {
+    const {quantity} = parseJMESPath(axis?.search_quantity)
+    const filter = filterData[quantity]
+    const title = axis.title || filter?.label || getDisplayLabel(filter)
+    const dtype = filter?.dtype
+    const unit = axis.unit
+      ? new Unit(axis.unit)
+      : new Unit(filter?.unit || 'dimensionless').toSystem(units)
+
+    return {
+      ...axis,
+      title,
+      unit,
+      dtype,
+      quantity: quantity
+    }
+}
diff --git a/gui/src/components/search/Filter.js b/gui/src/components/search/Filter.js
index 3434600073..fb518d9a4a 100644
--- a/gui/src/components/search/Filter.js
+++ b/gui/src/components/search/Filter.js
@@ -15,7 +15,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { isNil, isArray, isEmpty } from 'lodash'
+import { isNil, isArray, isEmpty, capitalize, split } from 'lodash'
 import { searchQuantities } from '../../config'
 import {
   getDatatype,
@@ -23,7 +23,8 @@ import {
   getDeserializer,
   getDisplayLabel,
   DType,
-  multiTypes
+  multiTypes,
+  parseQuantityName
 } from '../../utils'
 import { Unit } from '../units/Unit'
 
@@ -139,7 +140,12 @@ export class Filter {
     this.description = params?.description || def?.description
     this.unit = params?.unit || def?.unit
     this.dimension = def?.unit ? new Unit(def?.unit).dimension() : 'dimensionless'
-    this.label = params?.label || getDisplayLabel(def)
+    function getLabel(quantity) {
+      if (isNil(quantity)) return ''
+      const {path} = parseQuantityName(quantity)
+      return capitalize(split(path, '.').slice(-1)[0].replace(/_/g, ' '))
+    }
+    this.label = params?.label || getDisplayLabel(def) || getLabel(this.quantity)
     this.parent = parent
     this.group = params.group
     this.placeholder = params?.placeholder
@@ -148,7 +154,7 @@ export class Filter {
       : params?.multiple
     this.exclusive = params?.exclusive === undefined ? true : params?.exclusive
     this.queryMode = params?.queryMode || (this.multiple ? 'any' : undefined)
-    this.options = params?.options || getEnumOptions(def)
+    this.options = params?.options || getEnumOptions(this.quantity)
     this.default = params?.default
     this.suggestion = !isNil(params?.suggestion) ? params.suggestion : (!isNil(def?.suggestion) ? def.suggestion : false)
     this.scale = params?.scale || 'linear'
@@ -184,7 +190,7 @@ export class Filter {
  */
 export function getEnumOptions(quantity, exclude = ['not processed']) {
   const metainfoOptions = searchQuantities?.[quantity]?.type?.type_data
-  if (isArray(metainfoOptions) && metainfoOptions.length > 0) {
+  if (isArray(metainfoOptions) && metainfoOptions.length > 0 && metainfoOptions.length <= 20) {
     const opt = {}
     for (const name of metainfoOptions) {
       opt[name] = {label: name}
@@ -206,11 +212,11 @@ export function getEnumOptions(quantity, exclude = ['not processed']) {
 export const getWidgetConfig = (quantity, dtype, aggregatable, scale) => {
   if (dtype === DType.Float || dtype === DType.Int || dtype === DType.Timestamp) {
     return {
-      x: {quantity},
+      x: {search_quantity: quantity},
       y: {scale: 'linear'},
       type: 'histogram',
       scale,
-      showinput: false,
+      show_input: false,
       autorange: false,
       nbins: 30,
       layout: {
@@ -223,10 +229,10 @@ export const getWidgetConfig = (quantity, dtype, aggregatable, scale) => {
     }
   } else if (aggregatable) {
     return {
-      quantity,
+      search_quantity: quantity,
       type: 'terms',
       scale: scale,
-      showinput: false,
+      show_input: false,
       layout: {
         sm: {w: 6, h: 9, minW: 3, minH: 3},
         md: {w: 6, h: 9, minW: 3, minH: 3},
diff --git a/gui/src/components/search/FilterRegistry.js b/gui/src/components/search/FilterRegistry.js
index 911385f308..9d48dffd95 100644
--- a/gui/src/components/search/FilterRegistry.js
+++ b/gui/src/components/search/FilterRegistry.js
@@ -27,7 +27,6 @@ import { Typography, Box } from '@material-ui/core'
 import { useErrors } from '../errors'
 
 // Containers for filter information
-export const defaultFilterGroups = {} // Mapping from a group name -> set of filter names
 export const defaultFilterData = {} // Stores data for each registered filter
 const dtypeMap = {
   [DType.Int]: 'int',
@@ -38,45 +37,6 @@ const dtypeMap = {
   [DType.Boolean]: 'bool'
 }
 
-// Ids for the filter menus: used to tie filter chips to a specific menu.
-const idElements = 'elements'
-const idStructure = 'structure'
-const idMethod = 'method'
-const idDFT = 'dft'
-const idTB = 'tb'
-const idGW = 'gw'
-const idBSE = 'bse'
-const idDMFT = 'dmft'
-const idPrecision = 'precision'
-const idProperties = 'properties'
-const idElectronic = 'electronic'
-const idSolarCell = 'solarcell'
-const idCatalyst = 'heterogeneouscatalyst'
-const idVibrational = 'vibrational'
-const idMechanical = 'mechanical'
-const idSpectroscopic = 'spectroscopic'
-const idMolecularDynamics = 'molecular_dynamics'
-const idGeometryOptimization = 'geometry_optimization'
-const idELN = 'eln'
-const idCustomQuantities = 'custom_quantities'
-const idAuthor = 'author'
-const idMetadata = 'metadata'
-const idOptimade = 'optimade'
-
-/**
- * Associates the given quantity name with the given group name in the filter
- * group data.
- *
- * @param {object} groups The groups to work on.
- * @param {str} groupName
- * @param {str} quantityName
- */
-function addToGroup(groups, groupName, quantityName) {
-  groups[groupName]
-    ? groups[groupName].add(quantityName)
-    : groups[groupName] = new Set([quantityName])
-}
-
 /**
  * This function is used to register a new filter within the SearchContext.
  * Filters are entities that can be searched through the filter panel and the
@@ -94,17 +54,21 @@ function addToGroup(groups, groupName, quantityName) {
  *  components.
  *
  * @param {string} name Name of the filter.
- * @param {string} group The group into which the filter belongs to. Groups
- * are used to e.g. in showing FilterSummaries about a group of filters.
  * @param {obj} config Data object containing options for the filter.
  */
-function saveFilter(name, group, config, parent) {
+function saveFilter(name, config, parent) {
   if (defaultFilterData[name]) {
     throw Error(`Trying to register filter "${name}"" multiple times.`)
   }
   const def = searchQuantities[name]
   const {path: quantity, schema} = parseQuantityName(name)
-  const newConf = {...(config || {}), quantity, schema, name: config?.name || def?.name || name, aggregatable: def?.aggregatable, group: group}
+  const newConf = {
+    ...(config || {}),
+    quantity,
+    schema,
+    name: config?.name || def?.name || name,
+    aggregatable: def?.aggregatable
+  }
   const data = defaultFilterData[name] || new Filter(def, newConf, parent)
   defaultFilterData[name] = data
   return data
@@ -114,12 +78,12 @@ function saveFilter(name, group, config, parent) {
  * Used to register a filter value for an individual metainfo quantity or
  * section.
  */
-function registerFilter(name, group, config, subQuantities) {
-  const parent = saveFilter(name, group, config)
+function registerFilter(name, config, subQuantities) {
+  const parent = saveFilter(name, config)
   if (subQuantities) {
     for (const subConfig of subQuantities) {
       const subname = `${name}.${subConfig.name}`
-      saveFilter(subname, group, subConfig, parent)
+      saveFilter(subname, subConfig, parent)
     }
   }
 }
@@ -127,11 +91,10 @@ function registerFilter(name, group, config, subQuantities) {
 /**
  * Used to register a filter that is based on a subset of quantity values.
  */
-function registerFilterOptions(name, group, target, label, description, options) {
+function registerFilterOptions(name, target, label, description, options) {
   const keys = Object.keys(options)
   registerFilter(
     name,
-    group,
     {
       aggs: {
         terms: {
@@ -179,7 +142,6 @@ const numberHistogramQuantity = {multiple: false, exclusive: false}
 // Filters that directly correspond to a metainfo value
 registerFilter(
   'results.material.structural_type',
-  idStructure,
   {
     ...termQuantity,
     scale: 'log',
@@ -188,32 +150,30 @@ registerFilter(
   }
 )
 
-registerFilter('results.material.functional_type', idStructure, termQuantityNonExclusive)
-registerFilter('results.material.compound_type', idStructure, termQuantityNonExclusive)
-registerFilter('results.material.material_name', idStructure, termQuantity)
-registerFilter('results.material.chemical_formula_hill', idElements, {...termQuantity, placeholder: "E.g. H2O2, C2H5Br"})
-registerFilter('results.material.chemical_formula_iupac', idElements, {...termQuantity, placeholder: "E.g. GaAs, SiC", label: 'Chemical formula IUPAC'})
-registerFilter('results.material.chemical_formula_reduced', idElements, {...termQuantity, placeholder: "E.g. H2NaO, ClNa"})
-registerFilter('results.material.chemical_formula_anonymous', idElements, {...termQuantity, placeholder: "E.g. A2B, A3B2C2"})
-registerFilter('results.material.n_elements', idElements, {...numberHistogramQuantity})
-registerFilter('results.material.symmetry.bravais_lattice', idStructure, termQuantity)
-registerFilter('results.material.symmetry.crystal_system', idStructure, termQuantity)
+registerFilter('results.material.functional_type', termQuantityNonExclusive)
+registerFilter('results.material.compound_type', termQuantityNonExclusive)
+registerFilter('results.material.material_name', termQuantity)
+registerFilter('results.material.chemical_formula_hill', {...termQuantity, placeholder: "E.g. H2O2, C2H5Br"})
+registerFilter('results.material.chemical_formula_iupac', {...termQuantity, placeholder: "E.g. GaAs, SiC", label: 'Chemical formula IUPAC'})
+registerFilter('results.material.chemical_formula_reduced', {...termQuantity, placeholder: "E.g. H2NaO, ClNa"})
+registerFilter('results.material.chemical_formula_anonymous', {...termQuantity, placeholder: "E.g. A2B, A3B2C2"})
+registerFilter('results.material.n_elements', {...numberHistogramQuantity})
+registerFilter('results.material.symmetry.bravais_lattice', termQuantity)
+registerFilter('results.material.symmetry.crystal_system', termQuantity)
 registerFilter(
   'results.material.symmetry.structure_name',
-  idStructure,
   {
     ...termQuantity,
     options: getEnumOptions('results.material.symmetry.structure_name', ['not processed', 'cubic perovskite'])
   }
 )
-registerFilter('results.material.symmetry.strukturbericht_designation', idStructure, termQuantity)
-registerFilter('results.material.symmetry.space_group_symbol', idStructure, {...termQuantity, placeholder: "E.g. Pnma, Fd-3m, P6_3mc"})
-registerFilter('results.material.symmetry.point_group', idStructure, {...termQuantity, placeholder: "E.g. 6mm, m-3m, 6/mmm"})
-registerFilter('results.material.symmetry.hall_symbol', idStructure, {...termQuantity, placeholder: "E.g. F 4d 2 3 -1d"})
-registerFilter('results.material.symmetry.prototype_aflow_id', idStructure, {...termQuantity, placeholder: "E.g. A_cF8_227_a"})
+registerFilter('results.material.symmetry.strukturbericht_designation', termQuantity)
+registerFilter('results.material.symmetry.space_group_symbol', {...termQuantity, placeholder: "E.g. Pnma, Fd-3m, P6_3mc"})
+registerFilter('results.material.symmetry.point_group', {...termQuantity, placeholder: "E.g. 6mm, m-3m, 6/mmm"})
+registerFilter('results.material.symmetry.hall_symbol', {...termQuantity, placeholder: "E.g. F 4d 2 3 -1d"})
+registerFilter('results.material.symmetry.prototype_aflow_id', {...termQuantity, placeholder: "E.g. A_cF8_227_a"})
 registerFilter(
   'results.material.topology',
-  idStructure,
   nestedQuantity,
   [
     {name: 'label', ...termQuantity},
@@ -264,7 +224,6 @@ registerFilter(
 )
 registerFilter(
   'results.material.elemental_composition',
-  idStructure,
   nestedQuantity,
   [
     {name: 'element', ...termQuantity},
@@ -274,7 +233,6 @@ registerFilter(
 )
 registerFilter(
   'results.material.topology.elemental_composition',
-  idStructure,
   nestedQuantity,
   [
     {name: 'element', ...termQuantity},
@@ -285,7 +243,6 @@ registerFilter(
 )
 registerFilter(
   'results.material.topology.active_orbitals',
-  idStructure,
   nestedQuantity,
   [
     {name: 'n_quantum_number', ...termQuantity},
@@ -300,19 +257,19 @@ registerFilter(
     {name: 'degeneracy', ...termQuantity}
   ]
 )
-registerFilter('results.method.method_name', idMethod, {...termQuantity, scale: 'log'})
-registerFilter('results.method.workflow_name', idMethod, {...termQuantity, scale: 'log'})
-registerFilter('results.method.simulation.program_name', idMethod, {...termQuantity, scale: 'log'})
-registerFilter('results.method.simulation.program_version', idMethod, termQuantity)
-registerFilter('results.method.simulation.program_version_internal', idMethod, termQuantity)
-registerFilter('results.method.simulation.precision.native_tier', idPrecision, {...termQuantity, placeholder: "E.g. VASP - accurate", label: 'Code-specific tier'})
-registerFilter('results.method.simulation.precision.k_line_density', idPrecision, {...numberHistogramQuantity, scale: 'log', label: 'k-line density'})
-registerFilter('results.method.simulation.precision.basis_set', idPrecision, {...termQuantity, scale: 'log'})
-registerFilter('results.method.simulation.precision.planewave_cutoff', idPrecision, {...numberHistogramQuantity, label: 'Plane-wave cutoff', scale: 'log'})
-registerFilter('results.method.simulation.precision.apw_cutoff', idPrecision, {...numberHistogramQuantity, label: 'APW cutoff', scale: 'log'})
-registerFilter('results.method.simulation.dft.core_electron_treatment', idDFT, termQuantity)
-registerFilter('results.method.simulation.dft.jacobs_ladder', idDFT, {...termQuantity, scale: 'log', label: 'Jacob\'s ladder'})
-registerFilter('results.method.simulation.dft.xc_functional_type', idDFT, {
+registerFilter('results.method.method_name', {...termQuantity, scale: 'log'})
+registerFilter('results.method.workflow_name', {...termQuantity, scale: 'log'})
+registerFilter('results.method.simulation.program_name', {...termQuantity, scale: 'log'})
+registerFilter('results.method.simulation.program_version', termQuantity)
+registerFilter('results.method.simulation.program_version_internal', termQuantity)
+registerFilter('results.method.simulation.precision.native_tier', {...termQuantity, placeholder: "E.g. VASP - accurate", label: 'Code-specific tier'})
+registerFilter('results.method.simulation.precision.k_line_density', {...numberHistogramQuantity, scale: 'log', label: 'k-line density'})
+registerFilter('results.method.simulation.precision.basis_set', {...termQuantity, scale: 'log'})
+registerFilter('results.method.simulation.precision.planewave_cutoff', {...numberHistogramQuantity, label: 'Plane-wave cutoff', scale: 'log'})
+registerFilter('results.method.simulation.precision.apw_cutoff', {...numberHistogramQuantity, label: 'APW cutoff', scale: 'log'})
+registerFilter('results.method.simulation.dft.core_electron_treatment', termQuantity)
+registerFilter('results.method.simulation.dft.jacobs_ladder', {...termQuantity, scale: 'log', label: 'Jacob\'s ladder'})
+registerFilter('results.method.simulation.dft.xc_functional_type', {
   ...termQuantity,
   scale: 'log',
   label: 'Jacob\'s ladder',
@@ -324,14 +281,14 @@ registerFilter('results.method.simulation.dft.xc_functional_type', idDFT, {
     'hybrid': {label: 'Hybrid'}
   }
 })
-registerFilter('results.method.simulation.dft.xc_functional_names', idDFT, {...termQuantityNonExclusive, scale: 'log', label: 'XC functional names'})
-registerFilter('results.method.simulation.dft.exact_exchange_mixing_factor', idDFT, {...numberHistogramQuantity, scale: 'log'})
-registerFilter('results.method.simulation.dft.hubbard_kanamori_model.u_effective', idDFT, {...numberHistogramQuantity, scale: 'log'})
-registerFilter('results.method.simulation.dft.relativity_method', idDFT, termQuantity)
-registerFilter('results.method.simulation.tb.type', idTB, {...termQuantity, scale: 'log'})
-registerFilter('results.method.simulation.tb.localization_type', idTB, {...termQuantity, scale: 'log'})
-registerFilter('results.method.simulation.gw.type', idGW, {...termQuantity, label: 'GW type'})
-registerFilter('results.method.simulation.gw.starting_point_type', idGW, {
+registerFilter('results.method.simulation.dft.xc_functional_names', {...termQuantityNonExclusive, scale: 'log', label: 'XC functional names'})
+registerFilter('results.method.simulation.dft.exact_exchange_mixing_factor', {...numberHistogramQuantity, scale: 'log'})
+registerFilter('results.method.simulation.dft.hubbard_kanamori_model.u_effective', {...numberHistogramQuantity, scale: 'log'})
+registerFilter('results.method.simulation.dft.relativity_method', termQuantity)
+registerFilter('results.method.simulation.tb.type', {...termQuantity, scale: 'log'})
+registerFilter('results.method.simulation.tb.localization_type', {...termQuantity, scale: 'log'})
+registerFilter('results.method.simulation.gw.type', {...termQuantity, label: 'GW type'})
+registerFilter('results.method.simulation.gw.starting_point_type', {
   ...termQuantity,
   scale: 'log',
   options: {
@@ -343,10 +300,10 @@ registerFilter('results.method.simulation.gw.starting_point_type', idGW, {
     'HF': {label: 'HF'}
   }
 })
-registerFilter('results.method.simulation.gw.basis_set_type', idGW, {...termQuantity, scale: 'log'})
-registerFilter('results.method.simulation.bse.type', idBSE, termQuantity)
-registerFilter('results.method.simulation.bse.solver', idBSE, termQuantity)
-registerFilter('results.method.simulation.bse.starting_point_type', idBSE, {
+registerFilter('results.method.simulation.gw.basis_set_type', {...termQuantity, scale: 'log'})
+registerFilter('results.method.simulation.bse.type', termQuantity)
+registerFilter('results.method.simulation.bse.solver', termQuantity)
+registerFilter('results.method.simulation.bse.starting_point_type', {
   ...termQuantity,
   scale: 'log',
   options: {
@@ -358,47 +315,48 @@ registerFilter('results.method.simulation.bse.starting_point_type', idBSE, {
     'HF': {label: 'HF'}
   }
 })
-registerFilter('results.method.simulation.bse.basis_set_type', idBSE, {...termQuantity, scale: 'log'})
-registerFilter('results.method.simulation.bse.gw_type', idBSE, {...termQuantity, scale: 'log', label: `GW type`})
-registerFilter('results.method.simulation.dmft.impurity_solver_type', idDMFT, {...termQuantity})
-registerFilter('results.method.simulation.dmft.magnetic_state', idDMFT, {...termQuantity})
-registerFilter('results.method.simulation.dmft.inverse_temperature', idDMFT, {...numberHistogramQuantity, scale: 'log'})
-registerFilter('results.method.simulation.dmft.u', idDMFT, {...numberHistogramQuantity, scale: 'log'})
-registerFilter('results.method.simulation.dmft.jh', idDMFT, {...numberHistogramQuantity, label: `JH`, scale: 'log'})
-registerFilter('results.method.simulation.dmft.analytical_continuation', idDMFT, {...termQuantity})
-registerFilter('results.eln.sections', idELN, termQuantity)
-registerFilter('results.eln.tags', idELN, termQuantity)
-registerFilter('results.eln.methods', idELN, termQuantity)
-registerFilter('results.eln.instruments', idELN, termQuantity)
-registerFilter('results.eln.lab_ids', idELN, {...termQuantity, label: 'Lab IDs'})
-registerFilter('results.eln.names', idELN, noAggQuantity)
-registerFilter('results.eln.descriptions', idELN, noAggQuantity)
-registerFilter('external_db', idAuthor, {...termQuantity, label: 'External database', scale: 'log'})
-registerFilter('authors.name', idAuthor, {...termQuantityNonExclusive, label: 'Author name'})
-registerFilter('upload_create_time', idAuthor, {...numberHistogramQuantity, scale: 'log'})
-registerFilter('entry_create_time', idAuthor, {...numberHistogramQuantity, scale: 'log'})
-registerFilter('datasets.dataset_name', idAuthor, {...termQuantityLarge, label: 'Dataset name'})
-registerFilter('datasets.doi', idAuthor, {...termQuantity, label: 'Dataset DOI'})
-registerFilter('datasets.dataset_id', idAuthor, termQuantity)
-registerFilter('domain', idMetadata, termQuantity)
-registerFilter('entry_id', idMetadata, termQuantity)
-registerFilter('entry_name', idMetadata, termQuantity)
-registerFilter('mainfile', idMetadata, termQuantity)
-registerFilter('upload_id', idMetadata, termQuantity)
-registerFilter('upload_name', idMetadata, termQuantity)
-registerFilter('published', idMetadata, termQuantity)
-registerFilter('main_author.user_id', idMetadata, termQuantity)
-registerFilter('quantities', idMetadata, {...noAggQuantity, label: 'Metainfo definition', queryMode: 'all'})
-registerFilter('sections', idMetadata, {...noAggQuantity, label: 'Metainfo sections', queryMode: 'all'})
-registerFilter('section_defs.definition_qualified_name', idMetadata, {...noAggQuantity, label: 'Section defs qualified name', queryMode: 'all'})
-registerFilter('entry_references.target_entry_id', idMetadata, {...noAggQuantity, label: 'Entry references target entry id', queryMode: 'all'})
-registerFilter('entry_type', idMetadata, {...noAggQuantity, label: 'Entry type', queryMode: 'all'})
-registerFilter('entry_name.prefix', idMetadata, {...noAggQuantity, label: 'Entry name', queryMode: 'all'})
-registerFilter('results.material.material_id', idMetadata, termQuantity)
-registerFilter('optimade_filter', idOptimade, {multiple: true, queryMode: 'all'})
-registerFilter('processed', idMetadata, {label: 'Processed', queryMode: 'all'})
-registerFilter('text_search_contents', idMetadata, {multiple: true, queryMode: 'all'})
-registerFilter('custom_quantities', idCustomQuantities, {
+registerFilter('results.method.simulation.bse.basis_set_type', {...termQuantity, scale: 'log'})
+registerFilter('results.method.simulation.bse.gw_type', {...termQuantity, scale: 'log', label: `GW type`})
+registerFilter('results.method.simulation.dmft.impurity_solver_type', {...termQuantity})
+registerFilter('results.method.simulation.dmft.magnetic_state', {...termQuantity})
+registerFilter('results.method.simulation.dmft.inverse_temperature', {...numberHistogramQuantity, scale: 'log'})
+registerFilter('results.method.simulation.dmft.u', {...numberHistogramQuantity, scale: 'log'})
+registerFilter('results.method.simulation.dmft.jh', {...numberHistogramQuantity, label: `JH`, scale: 'log'})
+registerFilter('results.method.simulation.dmft.analytical_continuation', {...termQuantity})
+registerFilter('results.eln.sections', termQuantity)
+registerFilter('results.eln.tags', termQuantity)
+registerFilter('results.eln.methods', termQuantity)
+registerFilter('results.eln.instruments', termQuantity)
+registerFilter('results.eln.lab_ids', {...termQuantity, label: 'Lab IDs'})
+registerFilter('results.eln.names', noAggQuantity)
+registerFilter('results.eln.descriptions', noAggQuantity)
+registerFilter('external_db', {...termQuantity, label: 'External database', scale: 'log'})
+registerFilter('authors.name', {...termQuantityNonExclusive, label: 'Author name'})
+registerFilter('upload_create_time', {...numberHistogramQuantity, scale: 'log'})
+registerFilter('entry_create_time', {...numberHistogramQuantity, scale: 'log'})
+registerFilter('datasets.dataset_name', {...termQuantityLarge, label: 'Dataset name'})
+registerFilter('datasets.doi', {...termQuantity, label: 'Dataset DOI'})
+registerFilter('datasets.dataset_id', termQuantity)
+registerFilter('domain', termQuantity)
+registerFilter('entry_id', termQuantity)
+registerFilter('entry_name', termQuantity)
+registerFilter('mainfile', termQuantity)
+registerFilter('upload_id', termQuantity)
+registerFilter('upload_name', termQuantity)
+registerFilter('published', termQuantity)
+registerFilter('main_author.user_id', termQuantity)
+registerFilter('quantities', {...noAggQuantity, label: 'Metainfo definition', queryMode: 'all'})
+registerFilter('sections', {...noAggQuantity, label: 'Metainfo sections', queryMode: 'all'})
+registerFilter('files', {...noAggQuantity, queryMode: 'all'})
+registerFilter('section_defs.definition_qualified_name', {...noAggQuantity, label: 'Section defs qualified name', queryMode: 'all'})
+registerFilter('entry_references.target_entry_id', {...noAggQuantity, label: 'Entry references target entry id', queryMode: 'all'})
+registerFilter('entry_type', {...noAggQuantity, label: 'Entry type', queryMode: 'all'})
+registerFilter('entry_name.prefix', {...noAggQuantity, label: 'Entry name', queryMode: 'all'})
+registerFilter('results.material.material_id', termQuantity)
+registerFilter('optimade_filter', {multiple: true, queryMode: 'all'})
+registerFilter('processed', {label: 'Processed', queryMode: 'all'})
+registerFilter('text_search_contents', {multiple: true, queryMode: 'all'})
+registerFilter('custom_quantities', {
   serializerExact: value => {
     const jsonStr = JSON.stringify(value)
     const result = encodeURIComponent(jsonStr)
@@ -426,7 +384,6 @@ registerFilter('custom_quantities', idCustomQuantities, {
 })
 registerFilter(
   'results.properties.spectroscopic.spectra.provenance.eels',
-  idSpectroscopic,
   {...nestedQuantity, label: 'Electron energy loss spectrum (EELS)'},
   [
     {name: 'detector_type', ...termQuantity},
@@ -437,7 +394,6 @@ registerFilter(
 )
 registerFilter(
   'results.properties.electronic.band_structure_electronic',
-  idElectronic,
   {...nestedQuantity, label: 'Band structure'},
   [
     {name: 'spin_polarized', label: 'Spin-polarized', ...termQuantityBool}
@@ -445,7 +401,6 @@ registerFilter(
 )
 registerFilter(
   'results.properties.electronic.dos_electronic',
-  idElectronic,
   {...nestedQuantity, label: 'Density of states'},
   [
     {name: 'spin_polarized', label: 'Spin-polarized', ...termQuantityBool}
@@ -453,7 +408,6 @@ registerFilter(
 )
 registerFilter(
   'results.properties.electronic.band_structure_electronic.band_gap',
-  idElectronic,
   nestedQuantity,
   [
     {name: 'type', ...termQuantity},
@@ -462,17 +416,15 @@ registerFilter(
 )
 registerFilter(
   'results.properties.electronic.band_gap',
-  idElectronic,
   nestedQuantity,
   [
     {name: 'type', ...termQuantity},
     {name: 'value', ...numberHistogramQuantity, scale: 'log'}
   ]
 )
-registerFilter('results.properties.electronic.band_gap.provenance.label', idElectronic, termQuantity)
+registerFilter('results.properties.electronic.band_gap.provenance.label', termQuantity)
 registerFilter(
   'results.properties.optoelectronic.solar_cell',
-  idSolarCell,
   nestedQuantity,
   [
     {name: 'efficiency', ...numberHistogramQuantity, scale: 'log'},
@@ -493,7 +445,6 @@ registerFilter(
 )
 registerFilter(
   'results.properties.catalytic.catalyst',
-  idCatalyst,
   nestedQuantity,
   [
     {name: 'characterization_methods', ...termQuantity},
@@ -505,7 +456,6 @@ registerFilter(
 )
 registerFilter(
   'results.properties.catalytic.reaction',
-  idCatalyst,
   nestedQuantity,
   [
     {name: 'name', ...termQuantity},
@@ -514,7 +464,6 @@ registerFilter(
 )
 registerFilter(
   'results.properties.catalytic.reaction.reaction_conditions',
-  idCatalyst,
   nestedQuantity,
   [
     {name: 'temperature', ...numberHistogramQuantity, scale: 'linear'},
@@ -527,7 +476,6 @@ registerFilter(
 )
 registerFilter(
   'results.properties.catalytic.reaction.products',
-  idCatalyst,
   nestedQuantity,
   [
     {name: 'name', ...termQuantityAllNonExclusive},
@@ -538,7 +486,6 @@ registerFilter(
 )
 registerFilter(
   'results.properties.catalytic.reaction.reactants',
-  idCatalyst,
   nestedQuantity,
   [
     {name: 'name', ...termQuantityAllNonExclusive},
@@ -549,7 +496,6 @@ registerFilter(
 )
 registerFilter(
   'results.properties.catalytic.reaction.rates',
-  idCatalyst,
   nestedQuantity,
   [
     {name: 'name', ...termQuantityAllNonExclusive},
@@ -573,7 +519,6 @@ registerFilter(
 )
 registerFilter(
   'results.properties.mechanical.bulk_modulus',
-  idMechanical,
   nestedQuantity,
   [
     {name: 'type', ...termQuantity},
@@ -582,7 +527,6 @@ registerFilter(
 )
 registerFilter(
   'results.properties.mechanical.shear_modulus',
-  idMechanical,
   nestedQuantity,
   [
     {name: 'type', ...termQuantity},
@@ -591,12 +535,10 @@ registerFilter(
 )
 registerFilter(
   'results.properties.available_properties',
-  idProperties,
   termQuantityAll
 )
 registerFilter(
   'results.properties.mechanical.energy_volume_curve',
-  idMechanical,
   nestedQuantity,
   [
     {name: 'type', ...termQuantity}
@@ -604,7 +546,6 @@ registerFilter(
 )
 registerFilter(
   'results.properties.geometry_optimization',
-  idGeometryOptimization,
   nestedQuantity,
   [
     {name: 'final_energy_difference', ...numberHistogramQuantity, scale: 'log'},
@@ -614,7 +555,6 @@ registerFilter(
 )
 registerFilter(
   'results.properties.thermodynamic.trajectory',
-  idMolecularDynamics,
   nestedQuantity,
   [
     {name: 'available_properties', ...termQuantityAll},
@@ -627,7 +567,6 @@ registerFilter(
 // query itself.
 registerFilter(
   'visibility',
-  idMetadata,
   {
     ...noQueryQuantity,
     default: 'visible',
@@ -639,7 +578,6 @@ registerFilter(
 // entries.
 registerFilter(
   'combine',
-  undefined,
   {
     ...noQueryQuantity,
     default: true,
@@ -650,9 +588,9 @@ registerFilter(
 // Exclusive: controls the way elements search is done.
 registerFilter(
   'exclusive',
-  undefined,
   {
     ...noQueryQuantity,
+    dtype: DType.Boolean,
     default: false,
     description: "Search for entries with compositions that only (exclusively) contain the selected atoms. The default is to return all entries that have at least (inclusively) the selected atoms."
   }
@@ -662,11 +600,10 @@ registerFilter(
 // into a single string.
 registerFilter(
   'results.material.elements',
-  idElements,
   {
     widget: {
-      quantity: 'results.material.elements',
-      type: 'periodictable',
+      search_quantity: 'results.material.elements',
+      type: 'periodic_table',
       scale: 'log',
       layout: {
         sm: {w: 12, h: 8, minW: 12, minH: 8},
@@ -697,7 +634,6 @@ registerFilter(
 // Electronic properties: subset of results.properties.available_properties
 registerFilterOptions(
   'electronic_properties',
-  idElectronic,
   'results.properties.available_properties',
   'Electronic properties',
   'The electronic properties that are present in an entry.',
@@ -713,7 +649,6 @@ registerFilterOptions(
 // Vibrational properties: subset of results.properties.available_properties
 registerFilterOptions(
   'vibrational_properties',
-  idVibrational,
   'results.properties.available_properties',
   'Vibrational properties',
   'The vibrational properties that are present in an entry.',
@@ -728,7 +663,6 @@ registerFilterOptions(
 // Mechanical properties: subset of results.properties.available_properties
 registerFilterOptions(
   'mechanical_properties',
-  idMechanical,
   'results.properties.available_properties',
   'Mechanical properties',
   'The mechanical properties that are present in an entry.',
@@ -742,7 +676,6 @@ registerFilterOptions(
 // Spectroscopic properties: subset of results.properties.available_properties
 registerFilterOptions(
   'spectroscopic_properties',
-  idSpectroscopic,
   'results.properties.available_properties',
   'Spectroscopic properties',
   'The spectroscopic properties that are present in an entry.',
@@ -754,7 +687,6 @@ registerFilterOptions(
 // Thermodynamical properties: subset of results.properties.available_properties
 registerFilterOptions(
   'thermodynamic_properties',
-  idMolecularDynamics,
   'results.properties.available_properties',
   'Thermodynamic properties',
   'The thermodynamic properties that are present.',
@@ -800,16 +732,16 @@ export function getStaticSuggestions(quantities, filterData) {
 }
 
 /**
- * HOC that is used to preload search filters from all required schemas. This
+ * HOC that is used to preload search quantities from all required schemas. This
  * simplifies the rendering logic by first loading all schemas before rendering
  * any components that rely on them.
  */
-export const withFilters = (WrappedComponent) => {
-  const WithFilters = ({initialFilters, ...rest}) => {
+export const withSearchQuantities = (WrappedComponent) => {
+  const WithFilters = ({initialSearchQuantities, ...rest}) => {
     // Here we load the python schemas, and determine which YAML/Nexus schemas
     // to load later.
-    const [yamlOptions, nexusOptions, initialFilterData, initialFilterGroups] = useMemo(() => {
-      const options = getOptions(initialFilters)
+    const [yamlOptions, nexusOptions, initialFilterData] = useMemo(() => {
+      const options = getOptions(initialSearchQuantities)
       const yamlOptions = options.filter((name) => name.includes(`#${yamlSchemaPrefix}`))
       const nexusOptions = options.filter((name) => name.startsWith('nexus.'))
 
@@ -817,44 +749,37 @@ export const withFilters = (WrappedComponent) => {
       // default filters.
       const defaultFilters = {}
       for (const [key, value] of Object.entries(defaultFilterData)) {
-        if (glob(key, [key], initialFilters?.exclude)) {
+        if (glob(key, [key], initialSearchQuantities?.exclude)) {
           defaultFilters[key] = value
-          if (value.group) {
-            addToGroup(defaultFilterGroups, value.group, key)
-          }
         }
       }
 
       // Load the python filters from plugins
       const pythonFilterData = {}
-      const mergedFilterGroups = {...defaultFilterGroups}
       for (const [name, def] of Object.entries(searchQuantities)) {
-        if (def.dynamic && glob(name, initialFilters?.include, initialFilters?.exclude)) {
+        if (def.dynamic && glob(name, initialSearchQuantities?.include, initialSearchQuantities?.exclude)) {
           const {path, schema} = parseQuantityName(name)
           const params = {
             name: path,
-            quantity: path,
+            quantity: name,
             schema,
             aggregatable: def.aggregatable
           }
           pythonFilterData[name] = new Filter(def, params)
-          addToGroup(mergedFilterGroups, idCustomQuantities, name)
         }
       }
 
       return [
         yamlOptions,
         nexusOptions,
-        {...defaultFilters, ...pythonFilterData},
-        mergedFilterGroups
+        {...defaultFilters, ...pythonFilterData}
       ]
-    }, [initialFilters])
+    }, [initialSearchQuantities])
 
     const metainfo = useGlobalMetainfo()
     const [loadingYaml, setLoadingYaml] = useState(yamlOptions.length)
     const [loadingNexus, setLoadingNexus] = useState(nexusOptions.length)
     const [filters, setFilters] = useState(initialFilterData)
-    const [filterGroups, setFilterGroups] = useState({...initialFilterGroups})
     const { raiseError } = useErrors()
 
     // Nexus metainfo is loaded here once metainfo is ready
@@ -863,7 +788,6 @@ export const withFilters = (WrappedComponent) => {
       const pkg = metainfo._packageDefs['nexus']
       const sections = pkg.section_definitions
       const nexusFilters = {}
-      const nexusFilterGroups = {}
       for (const section of sections) {
         const sectionPath = `nexus.${section.name}`
 
@@ -874,14 +798,14 @@ export const withFilters = (WrappedComponent) => {
         if (section?.more?.nx_category !== 'application') continue
 
         // Sections from which no quantities are included are skipped
-        if (!glob(sectionPath, initialFilters?.include, initialFilters?.exclude) && !initialFilters?.include.some(x => x.includes(sectionPath))) {
+        if (!glob(sectionPath, initialSearchQuantities?.include, initialSearchQuantities?.exclude) && !initialSearchQuantities?.include.some(x => x.includes(sectionPath))) {
           continue
         }
 
         // Add all included quantities recursively
         for (const [def, path, repeats] of getQuantities(section)) {
           const filterPath = `${sectionPath}.${path}`
-          const included = glob(filterPath, initialFilters?.include, initialFilters?.exclude)
+          const included = glob(filterPath, initialSearchQuantities?.include, initialSearchQuantities?.exclude)
           if (!included) continue
           const dtype = dtypeMap[getDatatype(def)]
           // TODO: For some Nexus quantities, the data types cannot be fetched.
@@ -895,28 +819,17 @@ export const withFilters = (WrappedComponent) => {
             repeats: repeats
           }
           nexusFilters[filterPath] = new Filter(def, params)
-          addToGroup(nexusFilterGroups, idCustomQuantities, filterPath)
         }
       }
       setFilters((old) => ({...old, ...nexusFilters}))
-      setFilterGroups((old) => {
-        const newGroups = {...old}
-        for (const [groupName, names] of Object.entries(nexusFilterGroups)) {
-          for (const quantityName of [...names]) {
-            addToGroup(newGroups, groupName, quantityName)
-          }
-        }
-        return newGroups
-      })
       setLoadingNexus(false)
-    }, [metainfo, nexusOptions, initialFilters])
+    }, [metainfo, nexusOptions, initialSearchQuantities])
 
     // YAML schemas are loaded here asynchronously
     useEffect(() => {
       if (!yamlOptions.length || !metainfo) return
       async function fetchSchemas(options) {
         const yamlFilters = {}
-        const yamlFilterGroups = {}
         for (const schemaPath of options) {
           let schemaDefinition
           try {
@@ -935,24 +848,14 @@ export const withFilters = (WrappedComponent) => {
               throw Error(`Unable to load the data type for ${path}.`)
             }
             const filterPath = `data.${path}${schemaSeparator}${schemaPath}`
-            const included = glob(filterPath, initialFilters?.include, initialFilters?.exclude)
+            const included = glob(filterPath, initialSearchQuantities?.include, initialSearchQuantities?.exclude)
             if (!included) continue
             const apiPath = `${filterPath}${dtypeSeparator}${dtype}`
             const {path: quantity, schema} = parseQuantityName(filterPath)
             yamlFilters[filterPath] = new Filter(def, {name: path, schema, quantity, requestQuantity: apiPath})
-            addToGroup(yamlFilterGroups, idCustomQuantities, filterPath)
           }
         }
         setFilters((old) => ({...old, ...yamlFilters}))
-        setFilterGroups((old) => {
-          const newGroups = {...old}
-          for (const [groupName, names] of Object.entries(yamlFilterGroups)) {
-            for (const quantityName of [...names]) {
-              addToGroup(newGroups, groupName, quantityName)
-            }
-          }
-          return newGroups
-        })
         setLoadingYaml(false)
       }
 
@@ -960,18 +863,18 @@ export const withFilters = (WrappedComponent) => {
       // and the required filters are registered from each.
       const yamlSchemas = new Set(yamlOptions.map(x => x.split('#').pop()))
       fetchSchemas(yamlSchemas)
-    }, [yamlOptions, metainfo, raiseError, initialFilters])
+    }, [yamlOptions, metainfo, raiseError, initialSearchQuantities])
 
     return (loadingYaml || loadingNexus)
       ? <Box margin={1}>
           <Typography>Loading the required schemas...</Typography>
         </Box>
-      : <WrappedComponent {...rest} initialFilterData={filters} initialFilterGroups={filterGroups}/>
+      : <WrappedComponent {...rest} initialSearchQuantities={filters}/>
   }
 
   WithFilters.displayName = `withFilter(${WrappedComponent.displayName || WrappedComponent.name})`
   WithFilters.propTypes = {
-    initialFilters: PropTypes.object // Determines which filters are available
+    initialSearchQuantities: PropTypes.object // Determines which filters are available
   }
 
   return WithFilters
diff --git a/gui/src/components/search/FilterRegistry.spec.js b/gui/src/components/search/FilterRegistry.spec.js
index 08c3fb53b2..6c75e670fb 100644
--- a/gui/src/components/search/FilterRegistry.spec.js
+++ b/gui/src/components/search/FilterRegistry.spec.js
@@ -17,10 +17,10 @@
  */
 import React from 'react'
 import { render, screen } from '../conftest.spec'
-import { withFilters } from './FilterRegistry'
+import { withSearchQuantities } from './FilterRegistry'
 
-const TestComponent = withFilters(({initialFilterData}) => {
-  return Object.keys(initialFilterData).map((filter) => <div key={filter}>{filter}</div>)
+const TestComponent = withSearchQuantities(({initialSearchQuantities}) => {
+  return Object.keys(initialSearchQuantities).map((filter) => <div key={filter}>{filter}</div>)
 })
 
 test.each([
@@ -28,7 +28,7 @@ test.each([
   ['nomad include', {include: ['mainfile']}, ['mainfile'], []],
   ['nomad exclude', {exclude: ['mainfile']}, [], ['mainfile']]
 ])('%s', async (name, config, include, exclude) => {
-  render(<TestComponent initialFilters={config}/>)
+  render(<TestComponent initialSearchQuantities={config}/>)
   for (const filter of include) {
     expect(await screen.findByText(filter, {exact: true})).toBeInTheDocument()
   }
diff --git a/gui/src/components/search/FilterTitle.js b/gui/src/components/search/FilterTitle.js
index 625a58af43..941a3537eb 100644
--- a/gui/src/components/search/FilterTitle.js
+++ b/gui/src/components/search/FilterTitle.js
@@ -21,7 +21,7 @@ import { Typography, Tooltip } from '@material-ui/core'
 import PropTypes from 'prop-types'
 import clsx from 'clsx'
 import { useSearchContext } from './SearchContext'
-import { inputSectionContext } from './input/InputSection'
+import { inputSectionContext } from './input/InputNestedObject'
 import { Unit } from '../units/Unit'
 import { useUnitContext } from '../units/UnitContext'
 import Ellipsis from '../visualization/Ellipsis'
@@ -36,8 +36,7 @@ const useStaticStyles = makeStyles(theme => ({
   },
   text: {
   },
-  title: {
-    fontWeight: 600,
+  subtitle2: {
     color: theme.palette.grey[800]
   },
   right: {
@@ -83,7 +82,7 @@ const FilterTitle = React.memo(({
       let finalUnit
       if (unit) {
         finalUnit = new Unit(unit).label()
-      } else if (filterData[quantity]?.unit) {
+      } else if (quantity && filterData[quantity]?.unit) {
         finalUnit = new Unit(filterData[quantity].unit).toSystem(units).label()
       }
       if (finalUnit) {
@@ -94,17 +93,14 @@ const FilterTitle = React.memo(({
   }, [filterData, quantity, units, label, unit, disableUnit])
 
   // Determine the final description
-  const finalDescription = description || filterData[quantity]?.description || ''
-  let tooltip = ''
-  if (finalDescription && quantity) {
-    tooltip = (
-      <>
-        <Typography>{finalLabel}</Typography>
-        <b>Description: </b>{finalDescription}<br/>
-        <b>Path: </b>{quantity}
-      </>
-    )
-  }
+  const finalDescription = description || (quantity && filterData[quantity]?.description) || ''
+  const tooltip = (quantity)
+    ? <>
+      <Typography>{finalLabel}</Typography>
+      <b>Description: </b>{finalDescription || '-'}<br/>
+      <b>Path: </b>{quantity}
+    </>
+    : finalDescription || ''
 
   return <Tooltip title={tooltip} interactive enterDelay={400} enterNextDelay={400} {...(TooltipProps || {})}>
     <div className={clsx(className, styles.root,
@@ -114,7 +110,7 @@ const FilterTitle = React.memo(({
     )}>
       <Typography
         noWrap={noWrap}
-        className={clsx(styles.text, (!section) && styles.title)}
+        className={clsx(styles.text, (!section) && (variant === "subtitle2") && styles.subtitle2)}
         variant={variant}
         onMouseDown={onMouseDown}
         onMouseUp={onMouseUp}
diff --git a/gui/src/components/search/Query.spec.js b/gui/src/components/search/Query.spec.js
index f8c5f8d0b3..ebff06aa38 100644
--- a/gui/src/components/search/Query.spec.js
+++ b/gui/src/components/search/Query.spec.js
@@ -35,7 +35,7 @@ test.each([
         initialPagination={context.pagination}
         initialColumns={context.columns}
         initialRows={context.rows}
-        initialFilterMenus={context.filter_menus}
+        initialMenu={context?.menu}
         initialFiltersLocked={context.filters_locked}
         initialDashboard={context?.dashboard}
         initialFilterValues={{[quantity]: input}}
diff --git a/gui/src/components/search/SearchBar.spec.js b/gui/src/components/search/SearchBar.spec.js
index 4411240dad..2b49c9c78f 100644
--- a/gui/src/components/search/SearchBar.spec.js
+++ b/gui/src/components/search/SearchBar.spec.js
@@ -51,7 +51,7 @@ describe('searchbar queries', function() {
           initialPagination={context.pagination}
           initialColumns={context.columns}
           initialRows={context.rows}
-          initialFilterMenus={context.filter_menus}
+          initialMenu={context?.menu}
           initialFiltersLocked={context.filters_locked}
           initialDashboard={context?.dashboard}
           initialSearchSyntaxes={context?.search_syntaxes}
@@ -91,7 +91,7 @@ describe('suggestions: history', function() {
           initialPagination={context.pagination}
           initialColumns={context.columns}
           initialRows={context.rows}
-          initialFilterMenus={context.filter_menus}
+          initialMenu={context?.menu}
           initialFiltersLocked={context.filters_locked}
           initialDashboard={context?.dashboard}
           initialSearchSyntaxes={context?.search_syntaxes}
@@ -116,7 +116,7 @@ describe('suggestions: history', function() {
           initialPagination={context.pagination}
           initialColumns={context.columns}
           initialRows={context.rows}
-          initialFilterMenus={context.filter_menus}
+          initialMenu={context?.menu}
           initialFiltersLocked={context.filters_locked}
           initialDashboard={context?.dashboard}
           initialSearchSyntaxes={context?.search_syntaxes}
@@ -140,7 +140,7 @@ describe('suggestions: history', function() {
           initialPagination={context.pagination}
           initialColumns={context.columns}
           initialRows={context.rows}
-          initialFilterMenus={context.filter_menus}
+          initialMenu={context?.menu}
           initialFiltersLocked={context.filters_locked}
           initialDashboard={context?.dashboard}
           initialSearchSyntaxes={context?.search_syntaxes}
diff --git a/gui/src/components/search/SearchContext.js b/gui/src/components/search/SearchContext.js
index 67c6b072f7..bbedb85215 100644
--- a/gui/src/components/search/SearchContext.js
+++ b/gui/src/components/search/SearchContext.js
@@ -70,9 +70,9 @@ import { useErrors } from '../errors'
 import { combinePagination, addColumnDefaults } from '../datatable/Datatable'
 import UploadStatusIcon from '../uploads/UploadStatusIcon'
 import { getWidgetsObject } from './widgets/Widget'
-import { inputSectionContext } from './input/InputSection'
+import { inputSectionContext } from './input/InputNestedObject'
 import { SearchSuggestion } from './SearchSuggestion'
-import { withFilters } from './FilterRegistry'
+import { withSearchQuantities } from './FilterRegistry'
 import { useUnitContext } from '../units/UnitContext'
 
 const useWidthConstrainedStyles = makeStyles(theme => ({
@@ -209,11 +209,10 @@ export const SearchContextRaw = React.memo(({
   initialFiltersLocked,
   initialColumns,
   initialRows,
-  initialFilterMenus,
+  initialMenu,
   initialPagination,
   initialDashboard,
-  initialFilterData,
-  initialFilterGroups,
+  initialSearchQuantities,
   initialFilterValues,
   initialSearchSyntaxes,
   id,
@@ -239,10 +238,10 @@ export const SearchContextRaw = React.memo(({
   // Initialize the set of filters that are available in this context
   const {initialFilterPaths, initialFilterAbbreviations} = useMemo(() => {
     return {
-      initialFilterPaths: new Set(Object.keys(initialFilterData)),
-      initialFilterAbbreviations: getAbbreviations(initialFilterData)
+      initialFilterPaths: new Set(Object.keys(initialSearchQuantities)),
+      initialFilterAbbreviations: getAbbreviations(initialSearchQuantities)
     }
-  }, [initialFilterData])
+  }, [initialSearchQuantities])
 
   // The final set of columns
   const columns = useMemo(() => {
@@ -255,7 +254,7 @@ export const SearchContextRaw = React.memo(({
         throw Error(`Invalid JMESPath query in the app columns: ${option.quantity}`)
       }
       option.sortable = parseResults.quantity === option.quantity
-      const filter = initialFilterData[parseResults.quantity]
+      const filter = initialSearchQuantities[parseResults.quantity]
       const storageUnit = filter?.unit
       const displayUnit = option.unit
       const finalUnit = (storageUnit || displayUnit)
@@ -364,11 +363,11 @@ export const SearchContextRaw = React.memo(({
 
     // Add key, defaults, and custom overrides
     options = options.map((column) => ({...column, key: column.quantity}))
-    addColumnDefaults(options, undefined, initialFilterData)
+    addColumnDefaults(options, undefined, initialSearchQuantities)
     options = options.map((column) => ({...column, ...(overrides[column.quantity] || {})}))
 
     return options
-  }, [initialFilterData, initialColumns, user, units])
+  }, [initialSearchQuantities, initialColumns, user, units])
 
   // The final row configuration
   const rows = useMemo(() => {
@@ -376,9 +375,9 @@ export const SearchContextRaw = React.memo(({
   }, [initialRows])
 
   // The final menu configuration
-  const filterMenus = useMemo(() => {
-    return initialFilterMenus || undefined
-  }, [initialFilterMenus])
+  const menu = useMemo(() => {
+    return initialMenu
+  }, [initialMenu])
 
   // The final dashboard configuration
   const dashboard = useMemo(() => {
@@ -391,7 +390,7 @@ export const SearchContextRaw = React.memo(({
   // default values as specified in filter registry are loaded
   const [initialQuery, initialAggs, filterDefaults] = useMemo(() => {
     const filterDefaults = {}
-    for (const [key, value] of Object.entries(initialFilterData)) {
+    for (const [key, value] of Object.entries(initialSearchQuantities)) {
       if (!isNil(value.default)) {
         filterDefaults[key] = value.default
       }
@@ -403,11 +402,11 @@ export const SearchContextRaw = React.memo(({
       }
     }
     return [
-      parseQueries(initialFilterValues, initialFilterData, initialFilterAbbreviations.filterFullnames),
+      parseQueries(initialFilterValues, initialSearchQuantities, initialFilterAbbreviations.filterFullnames),
       initialAggs,
       filterDefaults
     ]
-  }, [initialFilterData, initialFilterAbbreviations, initialFilterValues, initialFilterPaths])
+  }, [initialSearchQuantities, initialFilterAbbreviations, initialFilterValues, initialFilterPaths])
 
   // Atoms + setters and getters are used instead of regular React states to
   // avoid re-rendering components that are not depending on these values. The
@@ -537,7 +536,7 @@ export const SearchContextRaw = React.memo(({
     // modified later.
     const filtersDataState = atom({
       key: `filtersData_${contextID}`,
-      default: initialFilterData
+      default: initialSearchQuantities
     })
 
     const filterNamesState = selector({
@@ -587,7 +586,7 @@ export const SearchContextRaw = React.memo(({
       default: initialPagination
     })
 
-    const guiLocked = parseQueries(initialFiltersLocked, initialFilterData, initialFilterAbbreviations.filterFullnames)
+    const guiLocked = parseQueries(initialFiltersLocked, initialSearchQuantities, initialFilterAbbreviations.filterFullnames)
     const lockedFamily = atomFamily({
       key: `lockedFamily_${contextID}`,
       default: (name) => guiLocked?.[name]
@@ -1200,7 +1199,7 @@ export const SearchContextRaw = React.memo(({
     resource,
     contextID,
     initialQuery,
-    initialFilterData,
+    initialSearchQuantities,
     initialFilterAbbreviations,
     initialFiltersLocked,
     initialPagination,
@@ -1674,10 +1673,9 @@ export const SearchContextRaw = React.memo(({
       resource,
       columns,
       rows,
-      filterMenus,
+      menu,
       filters,
       filterData: filtersData,
-      filterGroups: initialFilterGroups,
       filterFullnames,
       filterAbbreviations,
       searchSyntaxes: initialSearchSyntaxes,
@@ -1725,10 +1723,9 @@ export const SearchContextRaw = React.memo(({
     resource,
     rows,
     columns,
-    filterMenus,
+    menu,
     filters,
     filtersData,
-    initialFilterGroups,
     filterFullnames,
     filterAbbreviations,
     initialSearchSyntaxes,
@@ -1790,11 +1787,10 @@ SearchContextRaw.propTypes = {
   initialFiltersLocked: PropTypes.object,
   initialColumns: PropTypes.arrayOf(PropTypes.object),
   initialRows: PropTypes.object,
-  initialFilterMenus: PropTypes.object,
+  initialMenu: PropTypes.object,
   initialPagination: PropTypes.object,
   initialDashboard: PropTypes.object,
-  initialFilterData: PropTypes.object, // Determines which filters are available
-  initialFilterGroups: PropTypes.object, // Maps filter groups to a set of filter names
+  initialSearchQuantities: PropTypes.object, // Determines which quantities are available for search
   initialFilterValues: PropTypes.object, // Here one can provide default filter values
   initialSearchSyntaxes: PropTypes.object, // Determines which syntaxes are supported
   children: PropTypes.node,
@@ -1806,8 +1802,8 @@ SearchContextRaw.defaultProps = {
   suggestionHistorySize: 20
 }
 
-export const FreeformSearchContext = withFilters(SearchContextRaw)
-export const SearchContext = compose(withQueryString, withFilters)(SearchContextRaw)
+export const FreeformSearchContext = withSearchQuantities(SearchContextRaw)
+export const SearchContext = compose(withQueryString, withSearchQuantities)(SearchContextRaw)
 
 /**
  * Hook for accessing the current SearchContext.
diff --git a/gui/src/components/search/SearchContext.spec.js b/gui/src/components/search/SearchContext.spec.js
index be0e37b67c..282c4fe9df 100644
--- a/gui/src/components/search/SearchContext.spec.js
+++ b/gui/src/components/search/SearchContext.spec.js
@@ -134,7 +134,7 @@ describe.only('test that final column information is generated correctly', funct
   ])('%s', async (name, column, filter, label) => {
     const quantity = 'test_filter'
     const { result: resultUseSearchContext } = renderHook(() => useSearchContext(), { wrapper: (props) => <Wrapper
-      initialFilterData={{[quantity]: filter}}
+      initialSearchQuantities={{[quantity]: filter}}
       initialColumns={[{quantity, ...column}]}
       {...props}
     />})
diff --git a/gui/src/components/search/SearchMenu.js b/gui/src/components/search/SearchMenu.js
new file mode 100644
index 0000000000..521cbc0f1a
--- /dev/null
+++ b/gui/src/components/search/SearchMenu.js
@@ -0,0 +1,287 @@
+/*
+ * Copyright The NOMAD Authors.
+ *
+ * This file is part of NOMAD. See https://nomad-lab.eu for further info.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React, { useEffect, useMemo, useState, useCallback } from 'react'
+import PropTypes from 'prop-types'
+import { isEmpty } from 'lodash'
+import {
+  Menu as MenuMUI
+} from '@material-ui/core'
+import {
+  Menu,
+  MenuHeader,
+  MenuItem,
+  MenuContent,
+  MenuSubMenus,
+  MenuSettings
+} from './menus/Menu'
+import ArrowBackIcon from '@material-ui/icons/ArrowBack'
+import MoreVert from '@material-ui/icons/MoreVert'
+import { Action } from '../Actions'
+import { useSearchContext } from './SearchContext'
+import { delay, camelCase } from '../../utils'
+import InputTerms from './input/InputTerms'
+import InputHistogram from './input/InputHistogram'
+import InputPeriodicTable from './input/InputPeriodicTable'
+import InputNestedObject from './input/InputNestedObject'
+import InputVisibility from './input/InputVisibility'
+import InputDefinitions from './input/InputDefinitions'
+import InputOptimade from './input/InputOptimade'
+import InputCustomQuantities from './input/InputCustomQuantities'
+import { InputGrid, InputGridItem } from './input/InputGrid'
+
+function createItems(items, visible) {
+  return (items || []).map((item, index) => {
+    let props = Object.fromEntries(Object.entries(item).map(([key, value]) => [camelCase(key), value]))
+    props = {visible, ...props}
+    let Comp
+    switch (item.type) {
+      case 'terms':
+        Comp = InputTerms
+        break
+      case 'histogram':
+        Comp = InputHistogram
+        break
+      case 'periodic_table':
+        Comp = InputPeriodicTable
+        break
+      case 'nested_object':
+        Comp = InputNestedObject
+        props.children = createItems(item.items, visible)
+        break
+      case 'visibility':
+        Comp = InputVisibility
+        break
+      case 'definitions':
+        Comp = InputDefinitions
+        break
+      case 'optimade':
+        Comp = InputOptimade
+        break
+      case 'custom_quantities':
+        Comp = InputCustomQuantities
+        break
+      case 'menu':
+        Comp = MenuItem
+        props.disableButton = isEmpty(item.items)
+        props.id = index
+        props.level = item.indentation
+        break
+      default:
+        throw Error(`Unknown menu item type: ${item.type}.`)
+    }
+
+    return <InputGridItem
+      key={index}
+      disablePadding={item.type === 'menu'}
+      xs={item.type === 'menu' ? 12 : item.width}>
+        {Comp && <Comp {...props}/>}
+    </InputGridItem>
+  })
+}
+/**
+ * Creates an instance of FilterMenu based on the menu in the SearchContext.
+ */
+const SearchMenu = React.memo(() => {
+  const [selected, setSelected] = React.useState()
+  const [isSubMenuOpen, setIsSubMenuOpen] = React.useState(false)
+  const [loaded, setLoaded] = useState(false)
+  const {menu, useSetIsMenuOpen, useIsMenuOpen, useIsCollapsed, useSetIsCollapsed} = useSearchContext()
+  const [isMenuOpen, setIsMenuOpen] = [useIsMenuOpen(), useSetIsMenuOpen()]
+  const [isCollapsed, setIsCollapsed] = [useIsCollapsed(), useSetIsCollapsed()]
+  const handleMenuCollapse = useCallback(() => setIsCollapsed(old => !old), [setIsCollapsed])
+
+  // Rendering the submenus is delayed on the event queue: this makes loading
+  // the search page more responsive by first loading everything else.
+  useEffect(() => {
+    delay(() => { setLoaded(true) })
+  }, [])
+
+  useEffect(() => {
+    setIsSubMenuOpen(isMenuOpen)
+  }, [isMenuOpen])
+
+  const [anchorEl, setAnchorEl] = React.useState(null)
+  const isSettingsOpen = Boolean(anchorEl)
+
+  // Callbacks
+  const openMenu = useCallback((event) => {
+    setAnchorEl(event.currentTarget)
+  }, [])
+  const closeMenu = useCallback(() => {
+    setAnchorEl(null)
+  }, [])
+  const handleOpenChange = useCallback((value) => {
+    setIsMenuOpen(value)
+    setIsSubMenuOpen(value)
+  }, [setIsMenuOpen])
+
+  // Create the list of menu items
+  const menuItems = useMemo(
+    () => createItems(menu?.items || [], true),
+    [menu]
+  )
+
+  // Create the list of submenus
+  const subMenus = useMemo(() => {
+    return (menu?.items || [])
+      .map((item, index) =>
+        item.type === 'menu'
+          ? <SearchSubMenu
+            key={index}
+            menu={item}
+            selected={selected}
+            open={isSubMenuOpen}
+            visible={index === selected}
+            onOpenChange={handleOpenChange}
+          />
+          : null
+      )
+  }, [menu, selected, handleOpenChange, isSubMenuOpen])
+
+  return <Menu
+    size={menu?.size}
+    open={true}
+    collapsed={isCollapsed}
+    onCollapsedChanged={setIsCollapsed}
+    subMenuOpen={isSubMenuOpen}
+    visible={true}
+    selected={selected}
+    onSelectedChange={(value) => {
+      setIsMenuOpen(old => value !== selected ? true : !old)
+      setSelected(value)
+      setIsSubMenuOpen(old => value !== selected ? true : !old)
+    }}
+  >
+    <MenuHeader
+      title="Filters"
+      actions={<>
+        <Action
+          tooltip={'Collapse menu'}
+          onClick={handleMenuCollapse}
+        >
+          <ArrowBackIcon fontSize="small"/>
+        </Action>
+        <Action
+          tooltip="Options"
+          onClick={openMenu}
+        >
+          <MoreVert fontSize="small"/>
+        </Action>
+        <MenuMUI
+          anchorEl={anchorEl}
+          open={isSettingsOpen}
+          onClose={closeMenu}
+          getContentAnchorEl={null}
+          anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
+          transformOrigin={{ vertical: 'top', horizontal: 'right' }}
+          keepMounted
+        >
+          <div>
+            <MenuSettings/>
+          </div>
+        </MenuMUI>
+      </>}
+    />
+    <MenuContent>
+      <InputGrid>{menuItems}</InputGrid>
+    </MenuContent>
+    <MenuSubMenus>
+      {loaded && subMenus}
+    </MenuSubMenus>
+  </Menu>
+})
+
+/**
+ * Submenu that pops on the right side of the parent menu.
+ */
+const SearchSubMenu = React.memo(({
+  menu,
+  open,
+  visible,
+  onOpenChange
+}) => {
+  const [selected, setSelected] = React.useState()
+  const [isSubMenuOpen, setIsSubMenuOpen] = React.useState(false)
+
+  // Callbacks
+  const handleClose = useCallback(() => onOpenChange(false), [onOpenChange])
+  const handleOpenChange = useCallback((value) => {
+    setIsSubMenuOpen(value)
+  }, [])
+
+  // Create the list of menu items
+  const menuItems = useMemo(
+    () => createItems(menu.items, visible),
+    [menu.items, visible]
+  )
+
+  // Create the list of submenus
+  const subMenus = useMemo(() => {
+    return (menu.items || [])
+      .map((item, index) =>
+        item.type === 'menu'
+          ? <SearchSubMenu
+            key={index}
+            menu={item}
+            open={open && isSubMenuOpen}
+            visible={visible && index === selected}
+            onOpenChange={handleOpenChange}
+          />
+          : null
+      )
+  }, [menu, selected, handleOpenChange, isSubMenuOpen, open, visible])
+
+  return <Menu
+    size={menu.size}
+    open={open}
+    subMenuOpen={open && isSubMenuOpen}
+    visible={visible}
+    selected={selected}
+    onSelectedChange={(value) => {
+      setSelected(value)
+      setIsSubMenuOpen(old => value !== selected ? true : !old)
+    }}
+  >
+    <MenuHeader
+      title={menu.title}
+      actions={<>
+        <Action
+          tooltip={'Close menu'}
+          onClick={handleClose}
+        >
+          <ArrowBackIcon fontSize="small"/>
+        </Action>
+      </>}
+    />
+    <MenuContent>
+      <InputGrid>{menuItems}</InputGrid>
+    </MenuContent>
+    <MenuSubMenus>
+      {subMenus}
+    </MenuSubMenus>
+  </Menu>
+})
+SearchSubMenu.propTypes = {
+  menu: PropTypes.object,
+  open: PropTypes.bool,
+  visible: PropTypes.bool,
+  selected: PropTypes.number,
+  onOpenChange: PropTypes.func
+}
+
+export default SearchMenu
diff --git a/gui/src/components/search/SearchMenu.spec.js b/gui/src/components/search/SearchMenu.spec.js
new file mode 100644
index 0000000000..bfd7e8bd53
--- /dev/null
+++ b/gui/src/components/search/SearchMenu.spec.js
@@ -0,0 +1,100 @@
+/*
+ * Copyright The NOMAD Authors.
+ *
+ * This file is part of NOMAD. See https://nomad-lab.eu for further info.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React, { useMemo } from 'react'
+import { render, screen } from '../conftest.spec'
+import { SearchContextRaw } from './SearchContext'
+import SearchMenu from './SearchMenu'
+import { Filter } from './Filter'
+import { DType } from '../../utils'
+
+// We set an initial mock for the SearchContext module
+const mockSetFilter = jest.fn()
+const mockUseMemo = useMemo
+jest.mock('./SearchContext', () => ({
+    ...jest.requireActual('./SearchContext'),
+    useSearchContext: () => ({
+      ...jest.requireActual('./SearchContext').useSearchContext(),
+      useAgg: (quantity, visible, id, config) => {
+        const response = mockUseMemo(() => {
+          return visible
+            ? {data: quantity === 'my_histogram'
+              ? [{value: 1, count: 5}]
+              : [
+                {value: 'A', count: 6},
+                {value: 'B', count: 5},
+                {value: 'C', count: 4},
+                {value: 'D', count: 3},
+                {value: 'E', count: 2},
+                {value: 'F', count: 1}
+              ].slice(0, config.size)}
+            : undefined
+        }, [])
+        return response
+      },
+      useFilterState: jest.fn((quantity) => {
+        const response = mockUseMemo(() => {
+          return [undefined, mockSetFilter]
+        }, [])
+        return response
+      }),
+      useResults: jest.fn((quantity) => {
+        const response = mockUseMemo(() => {
+          return undefined
+        }, [])
+        return response
+      })
+    })
+}))
+
+describe('test menu items', () => {
+  test.each([
+    ['terms', {type: 'terms', search_quantity: 'my_terms'}, 'My terms'],
+    ['histogram', {type: 'histogram', x: {search_quantity: 'my_histogram'}}, 'My histogram'],
+    ['periodic table', {type: 'periodic_table', search_quantity: 'my_periodic_table'}, 'My periodic table'],
+    ['nested object', {type: 'nested_object', path: 'my_nested_object'}, 'My nested object'],
+    ['visibility', {type: 'visibility'}, 'Visibility'],
+    ['definitions', {type: 'definitions'}, 'Definitions'],
+    ['optimade', {type: 'optimade'}, 'Optimade query'],
+    ['custom quantities', {type: 'custom_quantities'}, 'Custom quantities'],
+    ['menu', {type: 'menu', 'title': 'Submenu'}, 'Submenu']
+  ])('%s', async (name, menuItem, text) => {
+    const mainmenu = {
+      items: [menuItem]
+    }
+    render(
+      <SearchContextRaw
+        resource="entries"
+        id='entries'
+        initialSearchQuantities={{
+          my_terms: new Filter(undefined, {quantity: 'my_terms', dtype: DType.String}),
+          my_histogram: new Filter(undefined, {quantity: 'my_histogram', dtype: DType.Int}),
+          my_periodic_table: new Filter(undefined, {quantity: 'my_periodic_table', dtype: DType.String}),
+          my_nested_object: new Filter(undefined, {quantity: 'my_nested_object', dtype: DType.String}),
+          visibility: new Filter(undefined, {quantity: 'visibility', dtype: DType.String, global: true}),
+          quantities: new Filter(undefined, {quantity: 'quantities', dtype: DType.String})
+        }}
+        initialMenu={mainmenu}
+      >
+        <SearchMenu/>
+      </SearchContextRaw>
+    )
+    // Test that the menu item is displayed
+    screen.getByText(text)
+  })
+})
diff --git a/gui/src/components/search/SearchPage.js b/gui/src/components/search/SearchPage.js
index 38f5ae72a9..5b57837468 100644
--- a/gui/src/components/search/SearchPage.js
+++ b/gui/src/components/search/SearchPage.js
@@ -20,8 +20,7 @@ import clsx from 'clsx'
 import PropTypes from 'prop-types'
 import { Box } from '@material-ui/core'
 import { makeStyles } from '@material-ui/core/styles'
-import FilterMainMenu from './menus/FilterMainMenu'
-import { collapsedMenuWidth } from './menus/FilterMenu'
+import SearchMenu from './SearchMenu'
 import SearchBar from './SearchBar'
 import Query from './Query.js'
 import { SearchResults } from './SearchResults'
@@ -47,9 +46,6 @@ const useStyles = makeStyles(theme => {
       height: '100%',
       zIndex: 2
     },
-    leftColumnCollapsed: {
-      maxWidth: `${collapsedMenuWidth}rem`
-    },
     center: {
       flexGrow: 1,
       height: '100%',
@@ -86,23 +82,12 @@ const SearchPage = React.memo(({
   header
 }) => {
   const styles = useStyles()
-  const {
-    useIsMenuOpen,
-    useSetIsMenuOpen,
-    useIsCollapsed,
-    useSetIsCollapsed
-  } = useSearchContext()
+  const {useIsMenuOpen, useSetIsMenuOpen} = useSearchContext()
   const [isMenuOpen, setIsMenuOpen] = [useIsMenuOpen(), useSetIsMenuOpen()]
-  const [isCollapsed, setIsCollapsed] = [useIsCollapsed(), useSetIsCollapsed()]
 
   return <div className={styles.root}>
-    <div className={clsx(styles.leftColumn, isCollapsed && styles.leftColumnCollapsed)}>
-      <FilterMainMenu
-        open={isMenuOpen}
-        onOpenChange={setIsMenuOpen}
-        collapsed={isCollapsed}
-        onCollapsedChange={setIsCollapsed}
-      />
+    <div className={clsx(styles.leftColumn)}>
+      <SearchMenu/>
     </div>
     <div className={styles.center} onClick={() => setIsMenuOpen(false)}>
       <Box margin={2.5} paddingBottom={3}>
diff --git a/gui/src/components/search/SearchPage.spec.js b/gui/src/components/search/SearchPage.spec.js
index bf0936a711..94619b2e5e 100644
--- a/gui/src/components/search/SearchPage.spec.js
+++ b/gui/src/components/search/SearchPage.spec.js
@@ -16,21 +16,43 @@
  * limitations under the License.
  */
 
-import React from 'react'
-import { render, startAPI, closeAPI } from '../conftest.spec'
-import { expectFilterMainMenu, expectSearchResults } from './conftest.spec'
+import React, { useMemo } from 'react'
+import { render, screen } from '../conftest.spec'
+import { expectMenu, expectSearchResults } from './conftest.spec'
 import { ui } from '../../config'
 import { SearchContext } from './SearchContext'
 import SearchPage from './SearchPage'
-import { minutes } from '../../setupTests'
 
-describe('', () => {
-  beforeAll(async () => {
-    await startAPI('tests.states.search.search', 'tests/data/search/searchpage')
-  })
-  afterAll(() => closeAPI())
+// We set an initial mock for the SearchContext module
+const mockSetFilter = jest.fn()
+const mockUseMemo = useMemo
+jest.mock('./SearchContext', () => ({
+    ...jest.requireActual('./SearchContext'),
+    useSearchContext: () => ({
+      ...jest.requireActual('./SearchContext').useSearchContext(),
+      useAgg: (quantity, visible, id, config) => {
+        const response = mockUseMemo(() => {
+          return undefined
+        }, [])
+        return response
+      },
+      useFilterState: jest.fn((quantity) => {
+        const response = mockUseMemo(() => {
+          return [undefined, mockSetFilter]
+        }, [])
+        return response
+      }),
+      useResults: jest.fn((quantity) => {
+        const response = mockUseMemo(() => {
+          return {data: [{}], pagination: {total: 1}}
+        }, [])
+        return response
+      })
+    })
+}))
 
-  test('renders search page correctly', async () => {
+describe('', () => {
+  test('render search page components', async () => {
     const context = ui.apps.options.entries
     render(
       <SearchContext
@@ -38,7 +60,7 @@ describe('', () => {
           initialPagination={context.pagination}
           initialColumns={context.columns}
           initialRows={context.rows}
-          initialFilterMenus={context.filter_menus}
+          initialMenu={context.menu}
           initialFiltersLocked={context.filters_locked}
           initialDashboard={context?.dashboard}
           initialSearchSyntaxes={context?.search_syntaxes}
@@ -47,8 +69,16 @@ describe('', () => {
         <SearchPage />
       </SearchContext>
     )
+    // Test that menu is shown
+    await expectMenu(context.menu)
 
-    await expectFilterMainMenu(context)
-    await expectSearchResults(context)
-  }, 5 * minutes)
+    // Test that search bar is shown
+    screen.getByPlaceholderText('Type your query or keyword here')
+
+    // Test that query is shown
+    screen.getByText('Your query will be shown here')
+
+    // Test that results table is shown
+    await expectSearchResults(context.columns)
+  })
 })
diff --git a/gui/src/components/search/SearchResults.spec.js b/gui/src/components/search/SearchResults.spec.js
index ca521c7583..cdfc0de37d 100644
--- a/gui/src/components/search/SearchResults.spec.js
+++ b/gui/src/components/search/SearchResults.spec.js
@@ -80,7 +80,7 @@ describe('test search columns', () => {
       <SearchContextRaw
         resource="entries"
         id='entries'
-        initialFilterData={{
+        initialSearchQuantities={{
           'my_float': new Filter(undefined, {quantity: 'my_float', dtype: DType.Float}),
           'my_boolean': new Filter(undefined, {quantity: 'my_boolean', dtype: DType.Boolean}),
           'my_float_array': new Filter(undefined, {quantity: 'my_float_array', dtype: DType.Float, shape: '*'}),
diff --git a/gui/src/components/search/conftest.spec.js b/gui/src/components/search/conftest.spec.js
index b2bf298476..0e49362b7a 100644
--- a/gui/src/components/search/conftest.spec.js
+++ b/gui/src/components/search/conftest.spec.js
@@ -30,7 +30,6 @@ import { format } from 'date-fns'
 import { DType, getDisplayLabel, parseJMESPath } from '../../utils'
 import { Unit } from '../units/Unit'
 import { ui } from '../../config'
-import { menuMap } from './menus/FilterMainMenu'
 
 /*****************************************************************************/
 // Renders
@@ -129,7 +128,7 @@ export async function expectWidgetTerms(widget, loaded, items, prompt, root = sc
     )
 
     // Test immediately displayed elements
-    await expectFilterTitle(widget.quantity)
+    await expectFilterTitle(widget.search_quantity)
 
     // Check that placeholder disappears
     if (!loaded) {
@@ -153,6 +152,28 @@ export async function expectWidgetTerms(widget, loaded, items, prompt, root = sc
     }
 }
 
+/**
+ * Tests that an InputItem is displayed.
+ *
+ * @param {string} item The item specification
+ * @param {object} root The container to work on.
+ */
+export async function expectInputItem(item, root = screen) {
+  root.getByText(item.label)
+}
+
+/**
+ * Tests that a WidgetHistogram is rendered with the given contents.
+ * @param {object} widget The widget setup
+ * @param {bool} loaded Whether the data is already loaded
+ */
+export async function expectWidgetHistogram(widget, root = screen) {
+    // Test immediately displayed elements
+    const xAxis = widget.x
+    const {quantity: x} = parseJMESPath(xAxis.search_quantity)
+    await expectFilterTitle(x, xAxis.title, xAxis.unit, undefined, undefined, root)
+}
+
 /**
  * Tests that a WidgetScatterPlot is rendered with the given contents.
  * @param {object} widget The widget setup
@@ -160,13 +181,13 @@ export async function expectWidgetTerms(widget, loaded, items, prompt, root = sc
  */
 export async function expectWidgetScatterPlot(widget, loaded, colorTitle, legend, root = screen) {
     // Test immediately displayed elements
-    const {quantity: x} = parseJMESPath(widget.x.quantity)
-    const {quantity: y} = parseJMESPath(widget.y.quantity)
+    const {quantity: x} = parseJMESPath(widget.x.search_quantity)
+    const {quantity: y} = parseJMESPath(widget.y.search_quantity)
     await expectFilterTitle(x)
     await expectFilterTitle(y)
     if (colorTitle) {
-      if (colorTitle.quantity) {
-        await expectFilterTitle(colorTitle.quantity)
+      if (colorTitle.search_quantity) {
+        await expectFilterTitle(colorTitle.search_quantity)
       } else {
         await expectFilterTitle(undefined, colorTitle.title, colorTitle.unit)
       }
@@ -190,7 +211,7 @@ export async function expectWidgetScatterPlot(widget, loaded, colorTitle, legend
  */
 export async function expectInputRange(widget, loaded, histogram, anchored, min, max, root = screen) {
     // Test header
-    await expectInputHeader(widget.x.quantity, true)
+    await expectInputHeader(widget.x.search_quantity, true)
 
     // Check histogram
     if (histogram) {
@@ -202,7 +223,7 @@ export async function expectInputRange(widget, loaded, histogram, anchored, min,
 
     // Test text elements if the component is not anchored
     if (!anchored) {
-      const data = defaultFilterData[widget.x.quantity]
+      const data = defaultFilterData[widget.x.search_quantity]
       const dtype = data.dtype
       if (dtype === DType.Timestamp) {
         expect(root.getByText('Start time')).toBeInTheDocument()
@@ -285,51 +306,23 @@ export async function expectPeriodicTableItems(elements, root = screen) {
 }
 
 /**
- * Tests that the correct FilterMainMenu items are displayed.
+ * Tests that the menu is displayed.
  * @param {object} context The used search context
  * @param {object} root The root element to perform the search on.
  */
-export async function expectFilterMainMenu(context, root = screen) {
-    // Check that menu item labels are displayed
-    const menuConfig = context.filter_menus
-    const menuItems = (menuConfig.include || Object.keys(menuConfig.options))
-      .filter(key => !menuConfig?.exclude?.includes(key))
-      .map(key => ({key, ...menuConfig.options[key]}))
-    for (const menuItem of menuItems) {
-      const label = menuItem.label
-      if (label) {
-        const labelElement = screen.getByTestId(`menu-item-label-${menuItem.key}`)
-        expect(labelElement).toBeInTheDocument()
-        expect(within(labelElement).getByText(label)).toBeInTheDocument()
-      }
-    }
-
-    // Check that action labels are displayed
-    const actionItems = []
-    for (const menuItem of menuItems) {
-      for (const key of menuItem?.actions?.include || []) {
-        actionItems.push(menuItem.actions.options[key])
-      }
-    }
-    for (const actionItem of actionItems) {
-      const actionLabel = actionItem.label
-      if (actionLabel) {
-        const labelElement = screen.getByText(actionLabel)
-        expect(labelElement).toBeInTheDocument()
-        expect(within(labelElement).getByText(actionLabel)).toBeInTheDocument()
-      }
-    }
-
-    // Check that clicking the menu items with a submenu opens up the menu
-    for (const menuItem of menuItems) {
-      if (menuMap[menuItem.key]) {
-        const labelMenu = screen.getByTestId(`menu-item-label-${menuItem.key}`)
-        const labelSubMenu = await screen.findByTestId(`filter-menu-header-${menuItem.key}`)
-        expect(labelSubMenu).not.toBeVisible()
-        await userEvent.click(labelMenu)
-        expect(labelSubMenu).toBeVisible()
+export async function expectMenu(menu, root = screen) {
+  // Main title should be shown
+  screen.getByText('Filters')
+
+  // Check that submenu buttons are displayed
+  for (const menuItem of menu.items) {
+    if (menuItem.type === 'menu') {
+      const title = menuItem.title
+      if (title) {
+        screen.getAllByText(title)
       }
     }
+  }
 }
 
 /**
@@ -337,7 +330,7 @@ export async function expectFilterMainMenu(context, root = screen) {
  * @param {object} context The used search context
  * @param {object} root The root element to perform the search on.
  */
-export async function expectSearchResults(context, root = screen) {
+export async function expectSearchResults(columns, root = screen) {
     // Wait until search results are in
     expect(await screen.findByText("search result", {exact: false})).toBeInTheDocument()
 
@@ -347,7 +340,7 @@ export async function expectSearchResults(context, root = screen) {
     const container = within(screen.getByTestId('search-results'))
 
     // Check that correct columns are displayed
-    const columnLabels = context.columns
+    const columnLabels = columns
       .filter((column) => column.selected)
       .map((column) => {
         const quantity = column.quantity
diff --git a/gui/src/components/search/input/InputCheckbox.js b/gui/src/components/search/input/InputCheckbox.js
deleted file mode 100644
index 54bf7ed87b..0000000000
--- a/gui/src/components/search/input/InputCheckbox.js
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright The NOMAD Authors.
- *
- * This file is part of NOMAD. See https://nomad-lab.eu for further info.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React, { useCallback } from 'react'
-import { makeStyles, useTheme } from '@material-ui/core/styles'
-import {
-  FormControlLabel,
-  Checkbox,
-  Tooltip,
-  Typography
-} from '@material-ui/core'
-import PropTypes from 'prop-types'
-import { isNil } from 'lodash'
-import clsx from 'clsx'
-import { useSearchContext, getValue } from '../SearchContext'
-
-const useStyles = makeStyles(theme => ({
-  root: {
-    width: '100%',
-    display: 'flex',
-    alignItems: 'flex-start',
-    justifyContent: 'center',
-    flexDirection: 'column',
-    boxSizing: 'border-box'
-  }
-}))
-
-/**
- * A checkbox where the selection controls a true/false value within a quantity.
- */
-const InputCheckbox = React.memo(({
-  quantity,
-  label,
-  description,
-  initialValue,
-  className,
-  classes,
-  'data-testid': testID
-}) => {
-  const theme = useTheme()
-  const styles = useStyles({classes: classes, theme: theme})
-  const {filterData, useFilterState, useFilterLocked} = useSearchContext()
-  const [filter, setFilter] = useFilterState(quantity)
-  const filterLocked = useFilterLocked(quantity)
-
-  // Determine the description and units
-  const def = filterData[quantity]
-  const descFinal = description || def?.description || ''
-  const labelFinal = label || def?.label
-  const locked = !isNil(filterLocked) && def.global
-  const val = getValue(def, filter, filterLocked, initialValue)
-
-  const handleChange = useCallback((event, value) => {
-    setFilter(value)
-  }, [setFilter])
-
-  return <div className={clsx(className, styles.root)} data-testid={testID}>
-    <Tooltip title={descFinal}>
-      <FormControlLabel
-        control={<Checkbox
-          color="secondary"
-          disabled={locked}
-          checked={val}
-          onChange={handleChange}
-        />}
-        label={<Typography>{labelFinal}</Typography>}
-      />
-    </Tooltip>
-  </div>
-})
-
-InputCheckbox.propTypes = {
-  quantity: PropTypes.string.isRequired,
-  label: PropTypes.string,
-  description: PropTypes.string,
-  initialValue: PropTypes.bool,
-  className: PropTypes.string,
-  classes: PropTypes.object,
-  'data-testid': PropTypes.string
-}
-
-export default InputCheckbox
-
-/**
- * A checkbox where the selection activates a specific value within a quantity.
- */
-const useInputCheckboxValueStyles = makeStyles(theme => ({
-  root: {
-    '& > :last-child': {
-      marginRight: -3
-    }
-  },
-  control: {
-    padding: 6
-  }
-}))
-export const InputCheckboxValue = React.memo(({
-  quantity,
-  description,
-  value,
-  className,
-  classes,
-  'data-testid': testID
-}) => {
-  const theme = useTheme()
-  const styles = useInputCheckboxValueStyles({classes: classes, theme: theme})
-  const {filterData, useFilterState} = useSearchContext()
-  const [filter, setFilter] = useFilterState(quantity)
-
-  // Determine the description and units
-  const def = filterData[quantity]
-  const descFinal = description || def?.description || ''
-
-  const handleChange = useCallback(() => {
-    setFilter(old => {
-      const newValue = old ? new Set(old) : new Set()
-      newValue.has(value) ? newValue.delete(value) : newValue.add(value)
-      return newValue
-    })
-  }, [setFilter, value])
-
-  return <div className={clsx(className, styles.root)} data-testid={testID}>
-    <Tooltip title={descFinal}>
-      <Checkbox
-        color="secondary"
-        checked={filter ? filter.has(value) : false}
-        onChange={handleChange}
-        className={styles.control}
-        size="small"
-      />
-    </Tooltip>
-  </div>
-})
-
-InputCheckboxValue.propTypes = {
-  quantity: PropTypes.string.isRequired,
-  description: PropTypes.string,
-  value: PropTypes.any,
-  className: PropTypes.string,
-  classes: PropTypes.object,
-  'data-testid': PropTypes.string
-}
diff --git a/gui/src/components/search/menus/FilterSubMenuCustomQuantities.js b/gui/src/components/search/input/InputCustomQuantities.js
similarity index 82%
rename from gui/src/components/search/menus/FilterSubMenuCustomQuantities.js
rename to gui/src/components/search/input/InputCustomQuantities.js
index bff2e151f9..7545a3e86d 100644
--- a/gui/src/components/search/menus/FilterSubMenuCustomQuantities.js
+++ b/gui/src/components/search/input/InputCustomQuantities.js
@@ -15,22 +15,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react'
+import React, { useCallback, useEffect, useMemo, useState } from 'react'
 import PropTypes from 'prop-types'
 import { isNil } from 'lodash'
-import { FilterSubMenu, filterMenuContext } from './FilterMenu'
 import {
   Box,
   Button,
   FormControl,
   InputLabel,
-  LinearProgress,
   MenuItem,
   Select,
   Typography
 } from '@material-ui/core'
-import { InputGrid, InputGridItem } from '../input/InputGrid'
+import InputHeader from '../input/InputHeader'
 import { useApi } from '../../api'
 import { useErrors } from '../../errors'
 import { useSearchContext } from '../SearchContext'
@@ -43,6 +40,7 @@ import { editQuantityComponents } from '../../editQuantity/EditQuantity'
 import { InputMetainfoControlled } from '../../search/input/InputMetainfo'
 import { DType, getDatatype, rsplit, parseQuantityName } from '../../../utils'
 import { InputTextField } from '../input/InputText'
+import Placeholder from '../../visualization/Placeholder'
 
 const types = {
   [DType.Int]: 'Integer',
@@ -190,7 +188,7 @@ const QuantityFilter = React.memo(({quantities, filter, onChange}) => {
   const availableOperators = quantityDef ? getOperators(quantityDef) : ['search']
 
   return (<React.Fragment>
-    <Box display="flex" flexWrap="wrap" flexDirection="row" alignItems="flex-start" marginTop={1}>
+    <Box display="flex" flexWrap="wrap" flexDirection="row" alignItems="flex-start">
       <Box marginBottom={1} width="100%">
         <InputMetainfoControlled
           options={options}
@@ -245,15 +243,10 @@ QuantityFilter.propTypes = {
   onChange: PropTypes.func.isRequired
 }
 
-const FilterSubMenuCustomQuantities = React.memo(({
-  id,
-  ...rest
-}) => {
+const InputCustomQuantities = React.memo(({visible, title, showHeader}) => {
   const metainfo = useGlobalMetainfo()
-  const {selected, open} = useContext(filterMenuContext)
   const {useFilterState} = useSearchContext()
   const [loaded, setLoaded] = useState(false)
-  const visible = open && id === selected
   const {api} = useApi()
   const {raiseError} = useErrors()
   const [query, setQuery] = useFilterState('custom_quantities')
@@ -381,71 +374,69 @@ const FilterSubMenuCustomQuantities = React.memo(({
     setAndFilters(andFilters || [{}])
   }, [query, setAndFilters])
 
+  let content
   if (!quantities) {
-    return (
-      <FilterSubMenu id={id} {...rest}>
-        <InputGrid>
-          <InputGridItem xs={12}>
-            <LinearProgress/>
-          </InputGridItem>
-        </InputGrid>
-      </FilterSubMenu>
-    )
-  }
-
-  if (quantities.length === 0) {
-    return (
-      <FilterSubMenu id={id} {...rest}>
-        <InputGrid>
-          <InputGridItem xs={12}>
-            <Typography>
-              Could not find valid quantities to search for. Make sure that you have access to the data and that the metainfo associated with the quantities can be loaded correctly.
-            </Typography>
-          </InputGridItem>
-        </InputGrid>
-      </FilterSubMenu>
-    )
-  }
-
-  return <FilterSubMenu id={id} {...rest}>
-    <InputGrid>
-      <InputGridItem xs={12}>
-        <Box marginTop={2}>
-          {andFilters.map((filter, index) => (
-            <Box key={index} marginY={1}>
-              <QuantityFilter
-                quantities={quantities}
-                filter={filter}
-                onChange={filter => handleFilterChange(filter, index)}
-              />
-            </Box>
-          ))}
-          <Box flexDirection="row" display="flex">
-            <Button
-              variant="contained" color="primary" onClick={handleAndClicked}
-            >And</Button>
-            <Box marginLeft={1}>
-              <Button
-                variant="contained" color="primary" onClick={handleClearClicked}
-                disabled={andFilters.length === 1 && Object.keys(andFilters[0]).length === 0}
-              >Clear</Button>
-            </Box>
-          </Box>
+    content = <Placeholder
+      variant="rect"
+      margin={0}
+    />
+  } else if (quantities.length === 0) {
+    content = <Typography>
+      Could not find valid quantities to search for. Make sure that you have access to the data and that the metainfo associated with the quantities can be loaded correctly.
+    </Typography>
+  } else {
+    content = <>
+      {andFilters.map((filter, index) => (
+        <Box key={index} marginBottom={1}>
+          <QuantityFilter
+            quantities={quantities}
+            filter={filter}
+            onChange={filter => handleFilterChange(filter, index)}
+          />
         </Box>
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <Box marginTop={2} display="flex" flexDirection="row" justifyContent="right">
+      ))}
+      <Box flexDirection="row" display="flex" marginBottom={2}>
+        <Button
+          variant="contained" color="primary" onClick={handleAndClicked}
+        >And</Button>
+        <Box marginLeft={1}>
           <Button
-            variant="contained" color="primary" onClick={handleSearchClicked}
-            disabled={!searchEnabled}
-          >Update search</Button>
+            variant="contained" color="primary" onClick={handleClearClicked}
+            disabled={andFilters.length === 1 && Object.keys(andFilters[0]).length === 0}
+          >Clear</Button>
         </Box>
-      </InputGridItem>
-    </InputGrid>
-  </FilterSubMenu>
+      </Box>
+      <Box marginTop={2} display="flex" flexDirection="row" justifyContent="right">
+        <Button
+          variant="contained" color="primary" onClick={handleSearchClicked}
+          disabled={!searchEnabled}
+        >Update search</Button>
+      </Box>
+    </>
+  }
+
+  return <div>
+    {showHeader && <InputHeader
+      label={title || 'Custom quantities'}
+      description="Use this field to search for quantities defined in custom schemas."
+      disableStatistics
+      disableWidget
+    />}
+    {/* We need to set a dummy height for the content with relative height/width to fill the parent correctly. */}
+    <Box minHeight="201px" height="1px" width="100%">
+      {content}
+    </Box>
+  </div>
 })
-FilterSubMenuCustomQuantities.propTypes = {
-  id: PropTypes.string
+
+InputCustomQuantities.propTypes = {
+  visible: PropTypes.bool,
+  title: PropTypes.string,
+  showHeader: PropTypes.bool
+}
+
+InputCustomQuantities.defaultProps = {
+  showHeader: true
 }
 
-export default FilterSubMenuCustomQuantities
+export default InputCustomQuantities
diff --git a/gui/src/components/search/menus/FilterSubMenuMetadata.js b/gui/src/components/search/input/InputDefinitions.js
similarity index 62%
rename from gui/src/components/search/menus/FilterSubMenuMetadata.js
rename to gui/src/components/search/input/InputDefinitions.js
index eafd01ee10..03612dc433 100644
--- a/gui/src/components/search/menus/FilterSubMenuMetadata.js
+++ b/gui/src/components/search/input/InputDefinitions.js
@@ -15,11 +15,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React, { useCallback, useEffect, useMemo, useState, useContext } from 'react'
+
+import React, { useCallback, useEffect, useMemo, useState } from 'react'
 import PropTypes from 'prop-types'
 import clsx from 'clsx'
-import { FilterSubMenu, filterMenuContext } from './FilterMenu'
-import { InputGrid, InputGridItem } from '../input/InputGrid'
 import { Box, Collapse, makeStyles } from '@material-ui/core'
 import { SectionMDef, SubSectionMDef, useGlobalMetainfo } from '../../archive/metainfo'
 import ExpandMoreIcon from '@material-ui/icons/ExpandMore'
@@ -29,9 +28,6 @@ import InputItem from '../input/InputItem'
 import { InputTextQuantity } from '../input/InputText'
 import { useErrors } from '../../errors'
 import { useDataStore } from '../../DataStore'
-import InputField from '../input/InputField'
-import InputRadio from '../input/InputRadio'
-import { useApi } from '../../api'
 import InputHeader from '../input/InputHeader'
 
 const filterProperties = def => !(def.name.startsWith('x_') || def.virtual)
@@ -147,18 +143,12 @@ Definition.propTypes = {
   className: PropTypes.string
 }
 
-const FilterSubMenuMetadata = React.memo(({
-  id,
-  ...rest
-}) => {
-  const {api} = useApi()
-  const {selected, open} = useContext(filterMenuContext)
-  const visible = open && id === selected
-  const authenticated = api?.keycloak?.authenticated
+const InputDefinitions = React.memo(({visible}) => {
   const dataStore = useDataStore()
   const globalMetainfo = useGlobalMetainfo()
   const [[options, tree], setOptions] = useState([[], {}])
   const {raiseError} = useErrors()
+
   useEffect(() => {
     if (!globalMetainfo || !visible) {
       return
@@ -194,80 +184,22 @@ const FilterSubMenuMetadata = React.memo(({
     setOptions([options, tree])
   }, [raiseError, dataStore, globalMetainfo, setOptions, visible])
 
-  return <FilterSubMenu id={id} {...rest}>
-    <InputGrid>
-      <InputGridItem xs={12}>
-        <InputRadio
-          quantity="visibility"
-          label="Visibility"
-          initialValue={authenticated ? 'visible' : 'public'}
-          options={{
-            all: {label: 'All', disabled: !authenticated, tooltip: 'Consider all entries.'},
-            public: {label: 'Public', disabled: false, tooltip: 'Consider all entries that can be publically downloaded, i.e. only published entries without embargo.'},
-            visible: {label: 'Visible', disabled: !authenticated, tooltip: 'Consider all entries that are visible to you. This includes entries with embargo or unpublished entries that belong to you or are shared with you.'},
-            shared: {label: 'Shared', disabled: !authenticated, tooltip: 'Only consider entries that belong to you or are shared with you.'},
-            user: {label: 'User', disabled: !authenticated, tooltip: 'Only consider entries that belong to you.'},
-            staging: {label: 'Unpublished', disabled: !authenticated, tooltip: 'Only search through unpublished entries.'}
-          }}
-        ></InputRadio>
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="entry_id"
-          visible={visible}
-          disableStatistics
-          disableOptions
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="upload_id"
-          visible={visible}
-          disableStatistics
-          disableOptions
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="upload_name"
-          visible={visible}
-          disableStatistics
-          disableOptions
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.material.material_id"
-          visible={visible}
-          disableStatistics
-          disableOptions
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="datasets.dataset_id"
-          visible={visible}
-          disableStatistics
-          disableOptions
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputHeader quantity="quantities" disableStatistics/>
-        <Box marginBottom={1}>
-          <InputTextQuantity
-            quantity="quantities"
-            suggestions={options}
-          />
-        </Box>
-        {Object.keys(tree).map((name, index) => (
-          <Definition node={tree[name]} name={name} path={name} key={index} />
-        ))}
-      </InputGridItem>
-    </InputGrid>
-  </FilterSubMenu>
+  return <>
+    <InputHeader quantity="quantities" label='Definitions' disableStatistics/>
+    <Box marginBottom={1}>
+      <InputTextQuantity
+        quantity="quantities"
+        suggestions={options}
+      />
+    </Box>
+    {Object.keys(tree).map((name, index) => (
+      <Definition node={tree[name]} name={name} path={name} key={index} />
+    ))}
+  </>
 })
-FilterSubMenuMetadata.propTypes = {
-  id: PropTypes.string
+
+InputDefinitions.propTypes = {
+  visible: PropTypes.bool
 }
 
-export default FilterSubMenuMetadata
+export default InputDefinitions
diff --git a/gui/src/components/search/input/InputField.spec.js b/gui/src/components/search/input/InputField.spec.js
deleted file mode 100644
index 56a5e3790b..0000000000
--- a/gui/src/components/search/input/InputField.spec.js
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright The NOMAD Authors.
- *
- * This file is part of NOMAD. See https://nomad-lab.eu for further info.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React from 'react'
-import { waitFor, within, waitForElementToBeRemoved } from '@testing-library/dom'
-import { startAPI, closeAPI, screen } from '../../conftest.spec'
-import { renderSearchEntry, expectInputHeader } from '../conftest.spec'
-import { defaultFilterData } from '../FilterRegistry'
-import InputField from './InputField'
-import userEvent from '@testing-library/user-event'
-
-const stateName = 'tests.states.search.search'
-const optionsStructural = ['bulk', '2D', 'molecule / cluster']
-const optionsProgramName = ['VASP', 'exciting', 'ABACUS', 'ABINIT', 'AFLOW']
-const optionsXC = [
-  'GGA_C_PBE_SOL',
-  'GGA_X_PBE_SOL',
-  'LDA_C_PZ',
-  'LDA_X_PZ'
-]
-
-describe('', () => {
-  const quantity = 'results.material.structural_type'
-  beforeEach(async () => {
-    await startAPI(stateName, 'tests/data/search/inputfield-structural-type')
-    renderSearchEntry(<InputField
-      quantity={quantity}
-      disableSearch
-      visible
-    />)
-  })
-  afterEach(() => closeAPI())
-
-  test('initial state is loaded correctly for quantity with fixed options', async () => {
-    // Test immediately displayed elements
-    const allOptions = getAllOptions(quantity)
-    await expectInputHeader(quantity)
-    for (const option of allOptions) {
-      expect(await screen.findByText(option)).toBeInTheDocument()
-    }
-
-    // Test that options become selectable after API call finishes
-    await expectOptions(optionsStructural, allOptions)
-  })
-})
-
-describe('', () => {
-  const quantity = 'results.method.simulation.program_name'
-  beforeEach(async () => {
-    await startAPI(stateName, 'tests/data/search/inputfield-program-name')
-    renderSearchEntry(<InputField
-      quantity={quantity}
-      visible
-      data-testid="inputfield"
-    />)
-  })
-  afterEach(() => closeAPI())
-
-  test('initial state is loaded correctly for quantity with dynamically loaded options', async () => {
-    // Test that placeholder is shown while loading
-    const placeholder = screen.queryByTestId('inputfield-placeholder')
-    expect(placeholder).toBeInTheDocument()
-
-    // Check that placeholder disappears
-    await waitForElementToBeRemoved(() => screen.queryByTestId('inputfield-placeholder'))
-
-    // Test header
-    await expectInputHeader(quantity)
-
-    // Test that options become selectable after API call finishes
-    await expectOptions(['VASP', 'exciting'], optionsProgramName)
-
-    // Test that the "show more" button is shown, but "show less" is not shown
-    expect(screen.getByText('Show more')).toBeInTheDocument()
-    expect(screen.queryByText('Show less')).not.toBeInTheDocument()
-  })
-})
-
-describe('', () => {
-  const quantity = 'results.material.structural_type'
-  beforeEach(async () => {
-    await startAPI(stateName, 'tests/data/search/inputfield-structural-type-edit')
-    renderSearchEntry(<InputField
-      quantity={quantity}
-      visible
-      data-testid="inputfield"
-    />)
-  })
-  afterEach(() => closeAPI())
-
-  test('selecting an option for an exlusive filter does not update the displayed options', async () => {
-    // Test that options are selectable after API call finishes
-    await expectOptions(optionsStructural, optionsStructural)
-
-    // Select 'bulk' and test that all options are still available.
-    const checkbox = queryByInputItemName('bulk')
-    await userEvent.click(checkbox)
-    await expectOptions(optionsStructural, optionsStructural)
-  })
-})
-
-describe('', () => {
-  const quantity = 'results.method.simulation.dft.xc_functional_names'
-  beforeEach(async () => {
-    await startAPI(stateName, 'tests/data/search/inputfield-xc-functional-names')
-    renderSearchEntry(<InputField
-      quantity={quantity}
-      visible
-      data-testid="inputfield"
-    />)
-  })
-  afterEach(() => closeAPI())
-
-  test('selecting an option for a non-exlusive filter updates the displayed options', async () => {
-    // Test that options are selectable after API call finishes
-    await expectOptions(optionsXC, optionsXC)
-
-    // Select PBE exchange and test that only PBE correlation is shown
-    // afterwards
-    const checkbox = queryByInputItemName('GGA_C_PBE_SOL')
-    await userEvent.click(checkbox)
-    await expectOptions(['GGA_C_PBE_SOL', 'GGA_X_PBE_SOL'], optionsXC, false)
-  })
-})
-
-describe('', () => {
-  const quantity = 'results.method.simulation.dft.xc_functional_names'
-  beforeEach(async () => {
-    await startAPI(stateName, 'tests/data/search/inputfield-xc-functional-names-suggestion')
-    renderSearchEntry(<InputField
-      quantity={quantity}
-      visible
-      data-testid="inputfield"
-    />)
-  })
-  afterEach(() => closeAPI())
-
-  test('search field is shown, suggestions are shown when typing, selecting suggested values works correctly', async () => {
-    // Wait for initial render
-    await expectOptions(optionsXC, optionsXC, false)
-
-    // See that the input field is shown and is wait until it is not disabled
-    const input = screen.getByPlaceholderText('Type here')
-    expect(input).toBeInTheDocument()
-    await waitFor(() => expect(input).not.toBeDisabled())
-
-    // Start typing a value, it is expected that a list of suggestions will be
-    // shown shortly afterwards
-    await userEvent.type(input, 'SOL')
-    const suggestions = ['GGA_C_PBE_SOL', 'GGA_X_PBE_SOL']
-    for (const suggestion of suggestions) {
-      await screen.findByMenuItem(suggestion)
-    }
-
-    // Select a suggested option by clicking it. This should update the list.
-    const suggestion = screen.getByMenuItem('GGA_C_PBE_SOL')
-    await userEvent.click(suggestion)
-    await expectOptions(suggestions, suggestions, false)
-  })
-})
-
-/**
- * Tests that only the given options are selectable within an InputField.
- * @param {array} selectable Selectable options
- * @param {array} all All options
- * @param {boolean} visible Whether the non-available options should still be
- * displayed in a disabled state.
- * @param {object} root The root element to perform the search on.
- */
-async function expectOptions(selectable, all, visible = true, root = screen) {
-  const availableSet = new Set(selectable)
-  await waitFor(() => {
-    for (const option of all) {
-      const inputCheckbox = queryByInputItemName(option)
-      if (availableSet.has(option)) {
-        expect(inputCheckbox).not.toHaveAttribute('disabled')
-      } else if (visible) {
-        expect(inputCheckbox).toHaveAttribute('disabled')
-      } else {
-        expect(inputCheckbox).toBe(null)
-      }
-    }
-  })
-}
-
-/**
- * Finds the checkbox corresponding to an InputItem with the given value.
- * @param {string} name The option value that is displayed
- * @returns {element} The checkbox input HTML element.
- */
-function queryByInputItemName(option, root = screen) {
-  const inputLabel = root.queryByText(option)
-  const inputCheckbox = inputLabel && within(inputLabel.closest('label')).getByRole('checkbox')
-  return inputCheckbox
-}
-
-/**
- * Returns the list of all the enumerated options that are available for a
- * quantity.
- * @param {string} quantity Quantity name
- * @returns {array} List of options for the given quantity.
- */
-function getAllOptions(quantity) {
-  return [...Object.values(defaultFilterData[quantity].options)].map(option => option.label)
-}
diff --git a/gui/src/components/search/input/InputGrid.js b/gui/src/components/search/input/InputGrid.js
index 56a21a40f9..35f0828fba 100644
--- a/gui/src/components/search/input/InputGrid.js
+++ b/gui/src/components/search/input/InputGrid.js
@@ -15,13 +15,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React from 'react'
+import React, { useContext } from 'react'
 import PropTypes from 'prop-types'
+import clsx from 'clsx'
 import {
   Grid,
   Divider,
   makeStyles
 } from '@material-ui/core'
+import { inputSectionContext } from './InputNestedObject'
 
 /**
  * For displaying a grid of input properties.
@@ -30,24 +32,33 @@ import {
  * prevent horizontal overflow. A padding is applied to the parent element as
  * described in https://v4.mui.com/components/grid/#negative-margin
  */
-const inputGridSpacing = 2
-const useInputGridStyles = makeStyles(theme => ({
-  root: {
-    paddingLeft: theme.spacing(inputGridSpacing / 2),
-    paddingRight: theme.spacing(inputGridSpacing / 2)
+
+/**
+ * For displaying an individual input filter, typically within a InputGrid.
+ */
+export const inputItemPaddingHorizontal = 0.75
+export const inputItemPaddingVertical = 1
+const useStyles = makeStyles(theme => ({
+  root: {},
+  padding: {
+    paddingLeft: theme.spacing(inputItemPaddingHorizontal),
+    paddingRight: theme.spacing(inputItemPaddingHorizontal)
   }
 }))
-export function InputGrid({children}) {
-  const styles = useInputGridStyles()
-  return <div className={styles.root}>
-    <Grid container spacing={inputGridSpacing} style={{marginTop: 0}}>
+
+export function InputGrid({className, disablePadding, children}) {
+  const styles = useStyles()
+  return <div className={clsx(className, styles.root, !disablePadding && styles.padding)}>
+    <Grid container spacing={0}>
       {children}
     </Grid>
   </div>
 }
 
 InputGrid.propTypes = {
-  children: PropTypes.any
+  children: PropTypes.any,
+  disablePadding: PropTypes.bool,
+  className: PropTypes.string
 }
 
 /**
@@ -55,25 +66,36 @@ InputGrid.propTypes = {
  */
 const useInputGridItemStyles = makeStyles(theme => ({
   root: {
-    marginBottom: theme.spacing(inputGridSpacing / 2)
   },
-  content: {
-    paddingLeft: theme.spacing(inputGridSpacing / 4),
-    paddingRight: theme.spacing(inputGridSpacing / 4)
+  padding: {
+    padding: theme.spacing(inputItemPaddingVertical, inputItemPaddingHorizontal, inputItemPaddingVertical, inputItemPaddingHorizontal)
   },
   divider: {
-    marginLeft: theme.spacing(-inputGridSpacing / 2),
-    marginRight: theme.spacing(-inputGridSpacing / 2),
-    marginTop: theme.spacing(-inputGridSpacing / 2),
-    marginBottom: theme.spacing(inputGridSpacing / 4),
     backgroundColor: theme.palette.grey[300]
+  },
+  paddingEnabledDivider: {
+    marginTop: theme.spacing(-inputItemPaddingVertical),
+    marginRight: theme.spacing(-2 * inputItemPaddingHorizontal),
+    marginLeft: theme.spacing(-2 * inputItemPaddingHorizontal)
+  },
+  paddingDisabled: {
+    marginRight: theme.spacing(-inputItemPaddingHorizontal),
+    marginLeft: theme.spacing(-inputItemPaddingHorizontal)
+  },
+  section: {
+    marginTop: theme.spacing(-2)
   }
 }))
-export function InputGridItem({classes, children, ...other}) {
+export function InputGridItem({classes, children, disablePadding, ...other}) {
+  const sectionContext = useContext(inputSectionContext)
+  const section = sectionContext?.section
   const styles = useInputGridItemStyles({classes: classes})
-  return <Grid item {...other} className={styles.root}>
-    <Divider className={styles.divider}/>
-    <div className={styles.content}>
+  return <Grid item {...other} className={clsx(styles.root, !disablePadding && styles.padding)}>
+    {section
+      ? <div className={styles.section}></div>
+      : <Divider className={clsx(styles.divider, disablePadding ? styles.paddingDisabled : styles.paddingEnabledDivider)}/>
+    }
+    <div className={clsx(disablePadding && styles.paddingDisabled)}>
       {children}
     </div>
   </Grid>
@@ -81,8 +103,10 @@ export function InputGridItem({classes, children, ...other}) {
 
 InputGridItem.propTypes = {
   classes: PropTypes.object,
-  children: PropTypes.any
+  children: PropTypes.any,
+  disablePadding: PropTypes.any
 }
 
 InputGridItem.defaultProps = {
+  xs: 12
 }
diff --git a/gui/src/components/search/input/InputHeader.js b/gui/src/components/search/input/InputHeader.js
index a6c0cd1e10..609bfdaed4 100644
--- a/gui/src/components/search/input/InputHeader.js
+++ b/gui/src/components/search/input/InputHeader.js
@@ -66,6 +66,7 @@ const useStyles = makeStyles(theme => ({
 const InputHeader = React.memo(({
   quantity,
   label,
+  unit,
   description,
   disableWidget,
   disableStatistics,
@@ -154,6 +155,7 @@ const InputHeader = React.memo(({
         <FilterTitle
           quantity={quantity}
           label={label}
+          unit={unit}
           description={description}
           TooltipProps={tooltipProps}
         />
@@ -168,8 +170,9 @@ const InputHeader = React.memo(({
 })
 
 InputHeader.propTypes = {
-  quantity: PropTypes.string.isRequired,
+  quantity: PropTypes.string,
   label: PropTypes.string,
+  unit: PropTypes.string,
   description: PropTypes.string,
   disableWidget: PropTypes.bool,
   disableStatistics: PropTypes.bool,
diff --git a/gui/src/components/search/input/InputRange.js b/gui/src/components/search/input/InputHistogram.js
similarity index 83%
rename from gui/src/components/search/input/InputRange.js
rename to gui/src/components/search/input/InputHistogram.js
index 16bce845d5..9a95c284a5 100644
--- a/gui/src/components/search/input/InputRange.js
+++ b/gui/src/components/search/input/InputHistogram.js
@@ -17,21 +17,20 @@
  */
 import React, { useState, useMemo, useCallback, useEffect, useRef, useContext } from 'react'
 import { makeStyles } from '@material-ui/core/styles'
+import { Box } from '@material-ui/core'
 import PropTypes from 'prop-types'
 import clsx from 'clsx'
 import { isNil } from 'lodash'
 import InputHeader from './InputHeader'
-import { inputSectionContext } from './InputSection'
+import { inputSectionContext } from './InputNestedObject'
 import { Quantity } from '../../units/Quantity'
 import { Unit } from '../../units/Unit'
 import { useUnitContext } from '../../units/UnitContext'
 import { DType, formatNumber } from '../../../utils'
-import { getInterval } from '../../plotting/common'
+import { getAxisConfig, getInterval } from '../../plotting/common'
 import { useSearchContext } from '../SearchContext'
 import PlotHistogram from '../../plotting/PlotHistogram'
 import { isValid, getTime } from 'date-fns'
-import { ActionCheckbox } from '../../Actions'
-import { autorangeDescription } from '../widgets/WidgetHistogram'
 
 /*
  * Component for displaying a numerical range as a slider/histogram together
@@ -45,30 +44,29 @@ const useStyles = makeStyles(theme => ({
   histogram: {
   }
 }))
-export const Range = React.memo(({
-  xAxis,
-  yAxis,
+export const Histogram = React.memo(({
+  x,
+  y,
   nSteps,
   visible,
   nBins,
-  disableHistogram,
+  showStatistics,
   disableXTitle,
   autorange,
-  showinput,
+  showInput,
   aggId,
   className,
   classes,
   'data-testid': testID
 }) => {
-  const {filterData, useAgg, useFilterState, useIsStatisticsEnabled} = useSearchContext()
+  const {filterData, useAgg, useFilterState} = useSearchContext()
   const sectionContext = useContext(inputSectionContext)
   const repeats = sectionContext?.repeats
-  const isStatisticsEnabled = useIsStatisticsEnabled()
   const styles = useStyles({classes})
-  const [filter, setFilter] = useFilterState(xAxis.quantity)
+  const [filter, setFilter] = useFilterState(x.search_quantity)
   const [minLocal, setMinLocal] = useState()
   const [maxLocal, setMaxLocal] = useState()
-  const [plotData, setPlotData] = useState({xAxis, yAxis})
+  const [plotData, setPlotData] = useState({xAxis: x, yAxis: y})
   const loading = useRef(false)
   const firstRender = useRef(true)
   const validRange = useRef()
@@ -81,13 +79,12 @@ export const Range = React.memo(({
   const [minInclusive, setMinInclusive] = useState(true)
   const [maxInclusive, setMaxInclusive] = useState(true)
   const highlight = Boolean(filter)
-  disableHistogram = isNil(disableHistogram) ? !isStatisticsEnabled : disableHistogram
 
   // Determine the description and units
-  const def = filterData[xAxis.quantity]
+  const def = filterData[x.search_quantity]
   const unitStorage = useMemo(() => { return new Unit(def?.unit || 'dimensionless') }, [def])
-  const discretization = xAxis.dtype === DType.Int ? 1 : undefined
-  const isTime = xAxis.dtype === DType.Timestamp
+  const discretization = x.dtype === DType.Int ? 1 : undefined
+  const isTime = x.dtype === DType.Timestamp
   const firstLoad = useRef(true)
 
   // We need to set a valid initial input state: otherwise the component thinks
@@ -117,8 +114,8 @@ export const Range = React.memo(({
       ? filter
       : filter instanceof Quantity
         ? filter.to(unitStorage)
-        : new Quantity(filter, xAxis.unit).to(unitStorage)
-  }, [isTime, xAxis.unit, unitStorage])
+        : new Quantity(filter, x.unit).to(unitStorage)
+  }, [isTime, x.unit, unitStorage])
 
   // Aggregation when the statistics are enabled: a histogram aggregation with
   // extended bounds based on the currently set filter range. Note: the config
@@ -164,7 +161,7 @@ export const Range = React.memo(({
       ? {type: 'histogram', buckets: nBins, exclude_from_search, extended_bounds}
       : {type: 'histogram', interval: discretization, exclude_from_search, extended_bounds}
   }, [filter, fromDisplayUnit, isTime, discretization, nBins, autorange])
-  const agg = useAgg(xAxis.quantity, visible && !disableHistogram, `${aggId}_histogram`, aggHistogramConfig)
+  const agg = useAgg(x.search_quantity, visible && showStatistics, `${aggId}_histogram`, aggHistogramConfig)
   useEffect(() => {
     if (!isNil(agg)) {
       firstLoad.current = false
@@ -174,16 +171,13 @@ export const Range = React.memo(({
   // Aggregation when the statistics are disabled: a simple min_max aggregation
   // is enough in order to get the slider range.
   const aggSliderConfig = useMemo(() => ({type: 'min_max', exclude_from_search: true}), [])
-  const aggSlider = useAgg(xAxis.quantity, visible && disableHistogram, `${aggId}_slider`, aggSliderConfig)
+  const aggSlider = useAgg(x.search_quantity, visible && !showStatistics, `${aggId}_slider`, aggSliderConfig)
 
   // Determine the global minimum and maximum values
   const [minGlobal, maxGlobal] = useMemo(() => {
     let minGlobal
     let maxGlobal
-    if (disableHistogram) {
-      minGlobal = aggSlider?.data?.[0]
-      maxGlobal = aggSlider?.data?.[1]
-    } else {
+    if (showStatistics) {
       const nBuckets = agg?.data?.length || 0
       if (nBuckets === 1) {
         minGlobal = agg.data[0].value
@@ -202,10 +196,13 @@ export const Range = React.memo(({
           maxGlobal = agg.data[agg.data.length - 1].value + (discretization ? 0 : agg.interval)
         }
       }
+    } else {
+      minGlobal = aggSlider?.data?.[0]
+      maxGlobal = aggSlider?.data?.[1]
     }
     firstRender.current = false
     return [minGlobal, maxGlobal]
-  }, [agg, aggSlider, disableHistogram, discretization])
+  }, [agg, aggSlider, showStatistics, discretization])
 
   const stepHistogram = agg?.interval
   const unavailable = isNil(minGlobal) || isNil(maxGlobal) || isNil(range)
@@ -222,10 +219,10 @@ export const Range = React.memo(({
       return undefined
     }
     const rangeSI = maxLocal - minLocal
-    const range = new Quantity(rangeSI, unitStorage.toDelta()).to(xAxis.unit).value()
-    const intervalCustom = getInterval(range, nSteps, xAxis.dtype)
-    return new Quantity(intervalCustom, xAxis.unit).to(unitStorage).value()
-  }, [maxLocal, minLocal, discretization, nSteps, xAxis.dtype, xAxis.unit, unitStorage])
+    const range = new Quantity(rangeSI, unitStorage.toDelta()).to(x.unit).value()
+    const intervalCustom = getInterval(range, nSteps, x.dtype)
+    return new Quantity(intervalCustom, x.unit).to(unitStorage).value()
+  }, [maxLocal, minLocal, discretization, nSteps, x.dtype, x.unit, unitStorage])
 
   // When filter changes, the plot data should not be updated.
   useEffect(() => {
@@ -249,27 +246,28 @@ export const Range = React.memo(({
 
     setPlotData({
       xAxis: {
-        quantity: xAxis.quantity,
-        unit: xAxis.unit,
+        search_quantity: x.search_quantity,
+        quantity: x.quantity,
+        unit: x.unit,
         unitStorage: unitStorage,
-        dtype: xAxis.dtype,
-        title: xAxis.title,
+        dtype: x.dtype,
+        title: x.title,
         min: minLocal,
         max: maxLocal
       },
-      yAxis,
+      yAxis: y,
       step: stepHistogram,
       data: agg.data
     })
-  }, [loading, nBins, agg, minLocal, maxLocal, stepHistogram, unitStorage, xAxis.quantity, xAxis.unit, xAxis.dtype, xAxis.title, xAxis.scale, yAxis])
+  }, [loading, nBins, agg, minLocal, maxLocal, stepHistogram, unitStorage, x.search_quantity, x.quantity, x.unit, x.dtype, x.title, x.scale, y])
 
   // Function for converting search values into the currently selected unit
   // system.
   const toInternal = useCallback(filter => {
     return (!isTime && unitStorage)
-      ? formatNumber(new Quantity(filter, unitStorage).to(xAxis.unit).value())
+      ? formatNumber(new Quantity(filter, unitStorage).to(x.unit).value())
       : filter
-  }, [unitStorage, isTime, xAxis.unit])
+  }, [unitStorage, isTime, x.unit])
 
   // If no filter has been specified by the user, the range is automatically
   // adjusted according to global min/max of the field. If filter is set, the
@@ -532,18 +530,18 @@ export const Range = React.memo(({
       maxInput={maxInput}
       minLocal={minLocal}
       maxLocal={maxLocal}
-      showinput={showinput}
+      showInput={showInput}
       stepSlider={stepSlider}
-      disableHistogram={disableHistogram}
+      disableHistogram={!showStatistics}
       disableXTitle={disableXTitle}
       data-testid={`${testID}-histogram`}
     />
   </div>
 })
 
-Range.propTypes = {
-  xAxis: PropTypes.object,
-  yAxis: PropTypes.object,
+Histogram.propTypes = {
+  x: PropTypes.object,
+  y: PropTypes.object,
   /* Target number of steps for the slider that is shown when statistics are
    * disabled. The actual number may vary, as the step is chosen to be a
    * human-readable value that depends on the range and the unit. */
@@ -552,21 +550,21 @@ Range.propTypes = {
    * enabled. */
   nBins: PropTypes.number,
   visible: PropTypes.bool,
-  /* Whether the histogram is disabled */
-  disableHistogram: PropTypes.bool,
+  /* Whether to show advanced statistics */
+  showStatistics: PropTypes.bool,
   /* Whether the x title is disabled */
   disableXTitle: PropTypes.bool,
   /* Set the range automatically according to data. */
   autorange: PropTypes.bool,
   /* Show the input fields for min and max value */
-  showinput: PropTypes.bool,
+  showInput: PropTypes.bool,
   aggId: PropTypes.string,
   className: PropTypes.string,
   classes: PropTypes.object,
   'data-testid': PropTypes.string
 }
 
-Range.defaultProps = {
+Histogram.defaultProps = {
   nSteps: 20,
   nBins: 30,
   aggId: 'default',
@@ -576,7 +574,7 @@ Range.defaultProps = {
 /**
  * A small wrapper around Range for use in the filter menus.
  */
-const useInputRangeStyles = makeStyles(theme => ({
+const useInputHistogramStyles = makeStyles(theme => ({
   root: {
     display: 'flex',
     flexDirection: 'column'
@@ -585,69 +583,64 @@ const useInputRangeStyles = makeStyles(theme => ({
     height: '8rem'
   }
 }))
-const InputRange = React.memo(({
-  label,
-  quantity,
+const InputHistogram = React.memo(({
+  title,
+  x,
+  y,
   description,
   nSteps,
   visible,
-  initialScale,
   nBins,
-  disableHistogram,
-  initialAutorange,
+  showHeader,
+  showInput,
+  showStatistics,
+  autorange,
   aggId,
   className,
   'data-testid': testID
 }) => {
-  const {filterData} = useSearchContext()
+  const {filterData, useIsStatisticsEnabled} = useSearchContext()
+  const isStatisticsEnabled = useIsStatisticsEnabled()
   const {units} = useUnitContext()
-  const styles = useInputRangeStyles()
-  const [scale, setScale] = useState(initialScale || filterData[quantity].scale)
-  const dtype = filterData[quantity].dtype
+  const styles = useInputHistogramStyles()
+  const [scaleState, setScaleState] = useState(y?.scale || filterData[x?.search_quantity].scale)
+  const dtype = filterData[x.search_quantity].dtype
   const isTime = dtype === DType.Timestamp
-  const [autorange, setAutorange] = useState(isNil(initialAutorange) ? isTime : initialAutorange)
-  const x = useMemo(() => (
-    {
-      quantity,
-      dtype,
-      unit: new Unit(filterData[quantity]?.unit || 'dimensionless').toSystem(units)
-    }
-  ), [quantity, filterData, dtype, units])
-  const y = useMemo(() => ({scale: scale}), [scale])
+  const autorangeFinal = isNil(autorange) ? isTime : autorange
+  showStatistics = isStatisticsEnabled && showStatistics
+
+  // Create final axis configs for the histogram
+  const xAxis = useMemo(() => getAxisConfig(x, filterData, units), [x, filterData, units])
+  const yAxis = useMemo(() => ({...y, scale: scaleState}), [scaleState, y])
 
   // Determine the description and title
-  const def = filterData[quantity]
+  const def = filterData[x.search_quantity]
   const descFinal = description || def?.description || ''
-  const labelFinal = label || def?.label
-
-  // Component for enabling/disabling autorange
-  const actions = <ActionCheckbox
-    value={autorange}
-    label="zoom"
-    tooltip={autorangeDescription}
-    onChange={(value) => setAutorange(value)}
-  />
+  const labelFinal = title || def?.label
 
   return <div className={clsx(styles.root, className)}>
-    <InputHeader
-      label={labelFinal}
-      quantity={quantity}
-      description={descFinal}
-      scale={scale}
-      onChangeScale={setScale}
-      disableStatistics={disableHistogram}
-      actions={actions}
-    />
-    <Range
-      xAxis={x}
-      yAxis={y}
+    {showHeader
+      ? <InputHeader
+        label={labelFinal}
+        quantity={x.search_quantity}
+        unit={x.unit}
+        description={descFinal}
+        scale={scaleState}
+        onChangeScale={setScaleState}
+        disableStatistics={!showStatistics}
+      />
+      : <Box marginTop={1.5}/>
+    }
+    <Histogram
+      x={xAxis}
+      y={yAxis}
       nSteps={nSteps}
       visible={visible}
       nBins={nBins}
-      disableHistogram={disableHistogram}
+      showStatistics={showStatistics}
       disableXTitle
-      autorange={autorange}
-      showinput
+      autorange={autorangeFinal}
+      showInput={showInput}
       aggId={aggId}
       classes={{histogram: styles.histogram}}
       data-testid={testID}
@@ -655,26 +648,31 @@ const InputRange = React.memo(({
   </div>
 })
 
-InputRange.propTypes = {
-  label: PropTypes.string,
-  quantity: PropTypes.string.isRequired,
+InputHistogram.propTypes = {
+  title: PropTypes.string,
   description: PropTypes.string,
+  x: PropTypes.object,
+  y: PropTypes.object,
   nSteps: PropTypes.number,
   nBins: PropTypes.number,
   visible: PropTypes.bool,
-  initialScale: PropTypes.string,
-  disableHistogram: PropTypes.bool,
-  initialAutorange: PropTypes.bool,
+  showHeader: PropTypes.bool,
+  showInput: PropTypes.bool,
+  showStatistics: PropTypes.bool,
+  autorange: PropTypes.bool,
   aggId: PropTypes.string,
   className: PropTypes.string,
   'data-testid': PropTypes.string
 }
 
-InputRange.defaultProps = {
+InputHistogram.defaultProps = {
   nSteps: 20,
   nBins: 30,
+  showHeader: true,
+  showInput: true,
+  showStatistics: true,
   aggId: 'default',
   'data-testid': 'inputrange'
 }
 
-export default InputRange
+export default InputHistogram
diff --git a/gui/src/components/search/input/InputHistogram.spec.js b/gui/src/components/search/input/InputHistogram.spec.js
new file mode 100644
index 0000000000..8779135514
--- /dev/null
+++ b/gui/src/components/search/input/InputHistogram.spec.js
@@ -0,0 +1,311 @@
+/*
+ * Copyright The NOMAD Authors.
+ *
+ * This file is part of NOMAD. See https://nomad-lab.eu for further info.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React, { useCallback, useMemo, useState } from 'react'
+import { fireEvent } from '@testing-library/dom'
+import { format } from 'date-fns'
+import { render, screen } from '../../conftest.spec'
+import { Filter } from '../Filter'
+import InputHistogram from './InputHistogram'
+import userEvent from '@testing-library/user-event'
+import { DType, formatNumber } from '../../../utils'
+import { useSearchContext, SearchContextRaw } from '../SearchContext'
+
+// We set an initial mock for the SearchContext module
+const mockSetFilter = jest.fn()
+jest.mock('../SearchContext', () => ({
+    ...jest.requireActual('../SearchContext'),
+    useSearchContext: jest.fn()
+}))
+
+describe('', () => {
+  // Provide a default implementation for the search context mock
+  beforeEach(() => {
+    useSearchContext.mockImplementation(() => ({
+        ...jest.requireActual('../SearchContext').useSearchContext(),
+        useAgg: (quantity, visible, id, config) => {
+          return useMemo(() => {
+            return visible
+              ? {
+                  data: [{value: 0, count: 10}, {value: 1, count: 20}, {value: 2, count: 20}],
+                  interval: 1
+                }
+              : undefined
+          }, [visible])
+        },
+        useFilterState: (quantity) => {
+          const response = useMemo(() => {
+            return [undefined, mockSetFilter]
+          }, [])
+          return response
+        }
+    }))
+  })
+
+  describe('test showHeader', () => {
+    test.each([
+      ['show header', {showHeader: true}],
+      ['do not show header', {showHeader: false}]
+    ])('%s', async (name, config) => {
+      renderInputHistogram(config, new Filter(undefined, {quantity: 'test'}))
+      if (config.showHeader) {
+        expect(screen.getByText('Test')).toBeInTheDocument()
+      } else {
+        expect(screen.queryByText('Test')).not.toBeInTheDocument()
+      }
+    })
+  })
+
+  describe('test title', () => {
+    test.each([
+      ['default title', {}, 'Test'],
+      ['custom title', {title: 'Custom title'}, 'Custom title']
+    ])('%s', async (name, config, expected) => {
+      renderInputHistogram(config, new Filter(undefined, {quantity: 'test'}))
+      expect(screen.getByText(expected)).toBeInTheDocument()
+    })
+  })
+
+  describe('test showStatistics', () => {
+    test.each([
+      ['show statistics', {showStatistics: true}],
+      ['do not show statistics', {showStatistics: false}]
+    ])('%s', async (name, config) => {
+      renderInputHistogram(config, new Filter(undefined, {quantity: 'test'}))
+    const option = screen.queryAllByText('1')
+    const scaling = screen.queryByText('linear')
+    if (config.showStatistics) {
+      expect(option).toHaveLength(2)
+      expect(scaling).toBeInTheDocument()
+    } else {
+      expect(option).toHaveLength(0)
+      expect(scaling).not.toBeInTheDocument()
+    }
+    })
+  })
+
+  describe('test showInput', () => {
+    test.each([
+      ['show input', {showInput: true}],
+      ['do not show input', {showInput: false}]
+    ])('%s', async (name, config) => {
+      renderInputHistogram(config, new Filter(undefined, {quantity: 'test'}))
+      if (config.showInput) {
+        expect(screen.getByText('min:')).toBeInTheDocument()
+        expect(screen.getByText('max:')).toBeInTheDocument()
+      } else {
+        expect(screen.queryByPlaceholderText('min:')).not.toBeInTheDocument()
+        expect(screen.queryByPlaceholderText('max:')).not.toBeInTheDocument()
+      }
+    })
+  })
+
+  describe('test invalid/valid numeric input', () => {
+    for (const isMin of [false, true]) {
+      const value = isMin ? 0 : 3
+      const field = isMin ? 'minimum' : 'maximum'
+      const message = `Invalid ${field} value.`
+      test.each([
+        ['1', true],
+        ['1.0', true],
+        ['-1.0', true],
+        ['-1.0e5', true],
+        ['-1.0e-5', true],
+        ['hello', false],
+        [' ', false]
+      ])(
+        `input: %s, valid: %s`,
+        async (input, valid) => {
+          const user = userEvent.setup()
+          renderInputHistogram({}, new Filter(undefined, {quantity: 'test'}))
+          const field = await screen.findByDisplayValue(value)
+          await user.clear(field)
+          await user.type(field, input)
+          await user.keyboard('[Enter]')
+          if (valid) {
+            expect(screen.queryByText(message)).toBeNull()
+          } else {
+            expect(screen.queryByText(message)).toBeInTheDocument()
+          }
+        }
+      )
+    }
+  })
+
+  describe('test input field change', () => {
+    // Custom aggregation data for this test
+    beforeEach(() => {
+      useSearchContext.mockImplementation(() => ({
+          ...jest.requireActual('../SearchContext').useSearchContext(),
+          useAgg: (quantity, visible, id, config) => {
+            return useMemo(() => {
+              return visible
+                ? {
+                    data: [{value: 0, count: 10}, {value: 1, count: 20}, {value: 2, count: 20}],
+                    interval: 1
+                  }
+                : undefined
+            }, [visible])
+          },
+          useFilterState: (quantity) => {
+            const [filter, setFilter] = useState()
+            const setFilterWrapper = useCallback((value) => {
+              setFilter(value)
+              mockSetFilter(value)
+            }, [])
+            const response = useMemo(() => {
+              return [filter, setFilterWrapper]
+            }, [filter, setFilterWrapper])
+            return response
+          }
+      }))
+    })
+    test.each([
+      ['min field', 0, 1, 3, 0, `left: 0%`],
+      ['max field', 3, 0, 1, 1, `left: 100%`]
+    ])('%s', async (name, value, gte, lte, slider, position) => {
+      const filter = new Filter(undefined, {quantity: 'test'})
+      const user = userEvent.setup()
+      renderInputHistogram({}, filter)
+      const sliders = screen.getAllByRole('slider')
+      slider = sliders[slider]
+
+      // Initially slider at the end
+      expect(slider).toHaveStyle(position)
+
+      // Type in a new value
+      const input = await screen.findByDisplayValue(value)
+      await user.clear(input)
+      await user.type(input, '1')
+      await user.keyboard('[Enter]')
+
+      // setFilter is triggered
+      expect(mockSetFilter.mock.calls).toHaveLength(1)
+      const argument = mockSetFilter.mock.calls[0][0]()
+      expect(argument.gte.value()).toBe(gte)
+      expect(argument.lte.value()).toBe(lte)
+
+      // Changing input moves slider
+      await testSliderMove(filter.dtype, 0, 3, input, slider, 50, false)
+    })
+  })
+
+  describe('test slider change', () => {
+    test.each([
+      ['min slider', 0, 1, 3, 0, 1, {key: 'Up', code: 'Up'}],
+      ['max slider', 3, 0, 2, 1, -1, {key: 'Down', code: 'Down'}]
+    ])('%s', async (name, value, gte, lte, slider, step, input) => {
+      renderInputHistogram({}, new Filter(undefined, {quantity: 'test'}))
+      const sliders = screen.getAllByRole('slider')
+      slider = sliders[slider]
+
+      // Change slider value with arrow keys
+      const inputMin = await screen.findByDisplayValue(value)
+      fireEvent.keyDown(slider, input)
+
+      // setFilter is triggered
+      expect(mockSetFilter.mock.calls).toHaveLength(1)
+      const argument = mockSetFilter.mock.calls[0][0]
+      expect(argument.gte.value()).toBe(gte)
+      expect(argument.lte.value()).toBe(lte)
+
+      // Moving slider changes input field
+      expect(mockSetFilter.mock.calls).toHaveLength(1)
+      expect(inputMin.value).toBe(formatNumber(value + step))
+    })
+  })
+
+  describe('test histograms with only one value', () => {
+    // Custom aggregation data for this test
+    beforeEach(() => {
+      useSearchContext.mockImplementation(() => ({
+          ...jest.requireActual('../SearchContext').useSearchContext(),
+          useAgg: (quantity, visible, id, config) => {
+              return useMemo(() => {
+                  return visible
+                      ? { data: [{ value: 1, count: 10 }], interval: 0 }
+                      : undefined
+              }, [visible])
+          }
+      }))
+    })
+    test.each([
+      ['integer', new Filter(undefined, {quantity: 'test', dtype: DType.Int}), 1],
+      ['float', new Filter(undefined, {quantity: 'test', dtype: DType.Float}), 1],
+      ['timestamp', new Filter(undefined, {quantity: 'test', dtype: DType.Timestamp}), 1]
+    ])('quantity: %s', async (name, filter, value) => {
+      renderInputHistogram({}, filter)
+
+      // Check that both text fields show the only available value
+      const inputValue = filter.dtype === DType.Timestamp
+        ? format(value, 'dd/MM/yyyy kk:mm')
+        : value
+      const inputs = await screen.findAllByDisplayValue(inputValue)
+      expect(inputs.length).toBe(2)
+
+      // Check that slider is disabled: trying to modify the sliders does not
+      // update the input fields.
+      const sliders = screen.getAllByRole('slider')
+      const sliderMin = sliders[0]
+      const sliderMax = sliders[1]
+      fireEvent.keyDown(sliderMin, {key: 'Up', code: 'Up'})
+      fireEvent.keyDown(sliderMax, {key: 'Down', code: 'Down'})
+      const inputsNew = await screen.findAllByDisplayValue(inputValue)
+      expect(inputsNew.length).toBe(2)
+    })
+  })
+})
+
+/**
+ * Tests that a slider moves to the given location when text input changes.
+ * @param {string} quantity The quantity name
+ * @param {number} min Minimum value of the slider
+ * @param {number} max Maximum value of the slider
+ * @param {*} input Text input element
+ * @param {*} slider MUI slider knob element
+ * @param {number} percentage The percentage to move to.
+ * @param {bool} isMax Is the max knob being moved.
+ * @param {bool} isMax Is the slider shown for a histogram.
+ */
+async function testSliderMove(dtype, min, max, input, slider, percentage, isMax) {
+  const discretization = (dtype === DType.Int) ? 1 : 0
+  const range = max - min + discretization
+  const value = min + range * (percentage / 100) - (isMax ? discretization : 0)
+
+  const user = userEvent.setup()
+  await user.clear(input)
+  await user.type(input, value.toString())
+  await user.keyboard('[Enter]')
+
+  const style = window.getComputedStyle(slider)
+  const left = parseFloat(style.getPropertyValue('left').slice(0, -1))
+  expect(left).toBeCloseTo(percentage, 8)
+}
+
+// Helper function for rendering
+function renderInputHistogram(config, filter) {
+  const searchQuantities = {test: filter}
+  render(
+    <SearchContextRaw
+      resource="entries"
+      id='entries'
+      initialSearchQuantities={searchQuantities}
+    >
+      <InputHistogram visible x={{search_quantity: filter.quantity}} {...config}/>
+    </SearchContextRaw>
+  )
+}
diff --git a/gui/src/components/search/input/InputMetainfo.spec.js b/gui/src/components/search/input/InputMetainfo.spec.js
index 0bc65da2fe..ab1bab88e4 100644
--- a/gui/src/components/search/input/InputMetainfo.spec.js
+++ b/gui/src/components/search/input/InputMetainfo.spec.js
@@ -40,8 +40,8 @@ test.each([
         initialPagination={context.pagination}
         initialColumns={context.columns}
         initialRows={context.rows}
-        initialFilters={context?.filters}
-        initialFilterMenus={context.filter_menus}
+        initialSearchQuantities={context?.search_quantities}
+        initialMenu={context?.menu}
         initialFiltersLocked={context.filters_locked}
         initialDashboard={context?.dashboard}
         initialSearchSyntaxes={context?.search_syntaxes}
diff --git a/gui/src/components/search/input/InputNestedObject.js b/gui/src/components/search/input/InputNestedObject.js
new file mode 100644
index 0000000000..2f92457c39
--- /dev/null
+++ b/gui/src/components/search/input/InputNestedObject.js
@@ -0,0 +1,102 @@
+/*
+ * Copyright The NOMAD Authors.
+ *
+ * This file is part of NOMAD. See https://nomad-lab.eu for further info.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React, { createContext } from 'react'
+import { makeStyles, useTheme } from '@material-ui/core/styles'
+// import { Divider } from '@material-ui/core'
+import PropTypes from 'prop-types'
+import clsx from 'clsx'
+import InputHeader from './InputHeader'
+import InputTooltip from './InputTooltip'
+import { InputGrid } from './InputGrid'
+import { useSearchContext } from '../SearchContext'
+
+/**
+ * InputSection can be used to group together quantities that should be searched
+ * together as an ES nested query:
+ * https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-nested-query.html
+ *
+ * By wrapping search components in InputSection, the API calls will be
+ * automatically performed as a nested query, and the visuals will change to
+ * indicate the grouping.
+ */
+export const inputSectionContext = createContext()
+const useStyles = makeStyles(theme => ({
+  root: {
+    width: '100%'
+  },
+  grid: {
+    marginTop: theme.spacing(1)
+  }
+}))
+const InputNestedObject = React.memo(({
+  title,
+  path,
+  description,
+  className,
+  showHeader,
+  classes,
+  children,
+  'data-testid': testID
+}) => {
+  const theme = useTheme()
+  const styles = useStyles({classes: classes, theme: theme})
+  const { filterData } = useSearchContext()
+
+  // Determine the description and units
+  const def = filterData[path]
+  const nested = def?.nested
+  const repeats = def?.repeats
+  const descFinal = description || def?.description || ''
+  const labelFinal = title || def?.label
+
+  return <InputTooltip>
+    <div className={clsx(className, styles.root)} data-testid={testID}>
+      {showHeader && <InputHeader
+        quantity={path}
+        label={labelFinal}
+        description={descFinal}
+        disableWidget
+        disableStatistics
+        />
+      }
+      <inputSectionContext.Provider value={{
+        section: path,
+        nested: nested,
+        repeats: repeats
+      }}>
+        <InputGrid disablePadding className={styles.grid}>{children}</InputGrid>
+      </inputSectionContext.Provider>
+    </div>
+  </InputTooltip>
+})
+
+InputNestedObject.propTypes = {
+  title: PropTypes.string,
+  path: PropTypes.string.isRequired,
+  description: PropTypes.string,
+  showHeader: PropTypes.bool,
+  className: PropTypes.string,
+  classes: PropTypes.object,
+  children: PropTypes.node,
+  'data-testid': PropTypes.string
+}
+InputNestedObject.defaultProps = {
+  showHeader: true
+}
+
+export default InputNestedObject
diff --git a/gui/src/components/search/menus/FilterSubMenuOptimade.js b/gui/src/components/search/input/InputOptimade.js
similarity index 80%
rename from gui/src/components/search/menus/FilterSubMenuOptimade.js
rename to gui/src/components/search/input/InputOptimade.js
index f42fa2cd38..d2dc7c7aa8 100644
--- a/gui/src/components/search/menus/FilterSubMenuOptimade.js
+++ b/gui/src/components/search/input/InputOptimade.js
@@ -15,11 +15,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react'
+import React, { useCallback, useEffect, useMemo, useState } from 'react'
 import PropTypes from 'prop-types'
-import { FilterSubMenu, filterMenuContext } from './FilterMenu'
-import { Box, TextField } from "@material-ui/core"
+import { TextField } from "@material-ui/core"
 import { useSearchContext } from "../SearchContext"
+import InputHeader from '../input/InputHeader'
 import AutoComplete from "@material-ui/lab/Autocomplete"
 import { useApi } from '../../api'
 import { debounce, isArray, isEmpty } from 'lodash'
@@ -32,16 +32,11 @@ const identifiers = Object.keys(searchQuantities)
   .map(key => key.slice(prefix.length))
   .sort()
 
-const FilterSubMenuOptimade = React.memo(({
-  id,
-  ...rest
-}) => {
+const InputOptimade = React.memo(({visible, title, showHeader}) => {
   const [suggestions, setSuggestions] = useState([['']])
   const [values, setValues] = useState([{value: '', valid: true, msg: ''}])
-  const {selected, open} = useContext(filterMenuContext)
   const {useFilterState} = useSearchContext()
   const {api} = useApi()
-  const visible = open && id === selected
   const [optimadeFilters, setOptimadeFilters] = useFilterState("optimade_filter")
 
   const renderSuggestion = useCallback((command, options, suggestions) => {
@@ -190,34 +185,56 @@ const FilterSubMenuOptimade = React.memo(({
     }
   }, [setFilter, setOptimadeFilter, validate, values])
 
-  return <FilterSubMenu id={id} {...rest}>
-    {visible && values && values.length === suggestions.length && values.map((value, index) => {
-      return <Box key={index} paddingLeft={2} paddingRight={2}>
-        <AutoComplete
-          options={suggestions[index]}
-          style={{width: '100%'}}
-          onChange={(event, value) => handleChange(event, value, index)}
-          onKeyDown={(event) => (event.key === 'Enter' && handleChange(event, value.value, index))}
-          value={value.value}
-          getOptionSelected={(option, value) => option === value}
-          getOptionLabel={option => (option && String(option)) || ''}
-          renderInput={params => (
-            <TextField
-              {...params}
-              variant='filled' label='Filter'
-              placeholder='Type optimade filter' margin='normal' fullWidth size='small'
-              onChange={event => handleInputChange(event.target.value, index)}
-              error={!!value.msg}
-              helperText={!!value.msg && value.msg}
-            />
-          )}
-        />
-      </Box>
-    })}
-  </FilterSubMenu>
+  return <>
+    {showHeader
+      ? <InputHeader
+        label={title || 'Optimade query'}
+        description="Use this field for creating an OPTIMADE query."
+        disableStatistics
+        disableWidget/>
+      : null
+    }
+    {(visible && values && values.length === suggestions.length)
+      ? <>
+        {values.map((value, index) =>
+          <AutoComplete
+            key={index}
+            options={suggestions[index]}
+            style={{width: '100%'}}
+            onChange={(event, value) => handleChange(event, value, index)}
+            onKeyDown={(event) => (event.key === 'Enter' && handleChange(event, value.value, index))}
+            value={value.value}
+            getOptionSelected={(option, value) => option === value}
+            getOptionLabel={option => (option && String(option)) || ''}
+            renderInput={params => (
+              <TextField
+                {...params}
+                variant='filled'
+                label='Filter'
+                placeholder='Type optimade filter'
+                margin='none'
+                fullWidth
+                size='small'
+                onChange={event => handleInputChange(event.target.value, index)}
+                error={!!value.msg}
+                helperText={!!value.msg && value.msg}
+              />
+            )}
+          />)}
+      </>
+      : null
+    }
+  </>
 })
-FilterSubMenuOptimade.propTypes = {
-  id: PropTypes.string
+
+InputOptimade.propTypes = {
+  visible: PropTypes.bool,
+  title: PropTypes.string,
+  showHeader: PropTypes.bool
+}
+
+InputOptimade.defaultProps = {
+  showHeader: true
 }
 
-export default FilterSubMenuOptimade
+export default InputOptimade
diff --git a/gui/src/components/search/input/InputPeriodicTable.js b/gui/src/components/search/input/InputPeriodicTable.js
index 7d74f53b67..a9a85241b9 100644
--- a/gui/src/components/search/input/InputPeriodicTable.js
+++ b/gui/src/components/search/input/InputPeriodicTable.js
@@ -21,9 +21,10 @@ import clsx from 'clsx'
 import { isNil } from 'lodash'
 import elementData from '../../../elementData'
 import { useResizeDetector } from 'react-resize-detector'
-import { Tooltip } from '@material-ui/core'
+import { Box, Tooltip } from '@material-ui/core'
 import InputHeader from './InputHeader'
-import InputCheckbox from './InputCheckbox'
+// eslint-disable-next-line no-unused-vars
+import InputTerms from './InputTerms'
 import { makeStyles, useTheme, lighten } from '@material-ui/core/styles'
 import { useSearchContext } from '../SearchContext'
 import { approxInteger } from '../../../utils'
@@ -165,6 +166,7 @@ Element.propTypes = {
 /**
  * Displays an interactive periodic table.
 */
+const options = {true: {label: 'only compositions that exclusively contain these atoms'}}
 const usePeriodicTableStyles = makeStyles(theme => ({
   root: {
     minHeight: 0, // added min-height: 0 to prevent relayouting when within flexbox
@@ -177,6 +179,7 @@ const usePeriodicTableStyles = makeStyles(theme => ({
     position: 'absolute',
     top: theme.spacing(-0.2),
     left: '10%',
+    right: '20%',
     textAlign: 'center'
   }
 }))
@@ -262,10 +265,14 @@ export const PeriodicTable = React.memo(({
       }
     </svg>
     <div className={styles.container}>
-      <InputCheckbox
-        quantity="exclusive"
-        label="only compositions that exclusively contain these atoms"
-      ></InputCheckbox>
+      <InputTerms
+        visible={visible}
+        searchQuantity="exclusive"
+        options={options}
+        showHeader={false}
+        showInput={false}
+        showStatistics={false}
+      />
     </div>
   </div>
 })
@@ -295,65 +302,75 @@ PeriodicTable.defaultProps = {
 const useInputPeriodicTableStyles = makeStyles(theme => ({
   root: {
     display: 'flex',
-    flexDirection: 'column'
+    flexDirection: 'column',
+    height: '30rem'
   }
 }))
 const InputPeriodicTable = React.memo(({
-    quantity,
-    label,
-    description,
-    visible,
-    initialScale,
-    anchored,
-    disableStatistics,
-    aggId,
-    className
-  }) => {
+  searchQuantity,
+  title,
+  description,
+  visible,
+  scale,
+  anchored,
+  showHeader,
+  showStatistics,
+  aggId,
+  className
+}) => {
   const styles = useInputPeriodicTableStyles()
-  const [scale, setScale] = useState(initialScale)
-  const {filterData} = useSearchContext()
+  const [scaleState, setScaleState] = useState(scale)
+  const {filterData, useIsStatisticsEnabled} = useSearchContext()
+  const isStatisticsEnabled = useIsStatisticsEnabled()
+  showStatistics = isStatisticsEnabled && showStatistics
 
   // Determine the description and title
-  const def = filterData[quantity]
+  const def = filterData[searchQuantity]
   const descFinal = description || def?.description || ''
-  const labelFinal = label || def?.label
+  const labelFinal = title || def?.label
 
   return <div className={clsx(styles.root, className)}>
-    <InputHeader
-      quantity={quantity}
-      label={labelFinal}
-      description={descFinal}
-      scale={scale}
-      onChangeScale={setScale}
-      disableStatistics={disableStatistics}
-      disableAggSize
-      anchored={anchored}
-    />
+    {showHeader
+      ? <InputHeader
+        quantity={searchQuantity}
+        label={labelFinal}
+        description={descFinal}
+        scale={scaleState}
+        onChangeScale={setScaleState}
+        disableStatistics={!showStatistics}
+        disableAggSize
+        anchored={anchored}
+      />
+      : <Box marginTop={1.5}/>
+    }
     <PeriodicTable
-      quantity={quantity}
+      quantity={searchQuantity}
       visible={visible}
-      scale={scale}
+      scale={scaleState}
       anchored={anchored}
-      disableStatistics={disableStatistics}
+      disableStatistics={!showStatistics}
       aggId={aggId}
     />
   </div>
 })
 
 InputPeriodicTable.propTypes = {
-  quantity: PropTypes.string,
-  label: PropTypes.string,
+  searchQuantity: PropTypes.string,
+  title: PropTypes.string,
   description: PropTypes.string,
+  scale: PropTypes.string,
+  showHeader: PropTypes.bool,
+  showStatistics: PropTypes.bool,
   visible: PropTypes.bool,
-  initialScale: PropTypes.string,
   anchored: PropTypes.bool,
-  disableStatistics: PropTypes.bool,
   aggId: PropTypes.string,
   className: PropTypes.string
 }
 
 InputPeriodicTable.defaultProps = {
-  initialScale: 'linear'
+  scale: 'linear',
+  showHeader: true,
+  showStatistics: true
 }
 
 export default InputPeriodicTable
diff --git a/gui/src/components/search/input/InputPeriodicTable.spec.js b/gui/src/components/search/input/InputPeriodicTable.spec.js
index 1aead838a5..d14ba3724d 100644
--- a/gui/src/components/search/input/InputPeriodicTable.spec.js
+++ b/gui/src/components/search/input/InputPeriodicTable.spec.js
@@ -15,60 +15,115 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React from 'react'
-import userEvent from '@testing-library/user-event'
-import { waitFor } from '@testing-library/dom'
-import { startAPI, closeAPI, screen } from '../../conftest.spec'
-import {
-  renderSearchEntry,
-  expectPeriodicTable,
-  expectPeriodicTableItems,
-  expectElement
-} from '../conftest.spec'
+import React, { useMemo } from 'react'
+import { render, screen } from '../../conftest.spec'
+import { Filter } from '../Filter'
 import InputPeriodicTable from './InputPeriodicTable'
+import userEvent from '@testing-library/user-event'
+import { useSearchContext, SearchContextRaw } from '../SearchContext'
 
-const quantity = 'results.material.elements'
-const stateName = 'tests.states.search.search'
+// We set an initial mock for the SearchContext module
+const mockSetFilter = jest.fn()
+jest.mock('../SearchContext', () => ({
+    ...jest.requireActual('../SearchContext'),
+    useSearchContext: jest.fn()
+}))
 
 describe('', () => {
-  beforeEach(async () => {
-    await startAPI(stateName, 'tests/data/search/inputperiodictable')
-    renderSearchEntry(<InputPeriodicTable
-      quantity={quantity}
-      visible
-    />
-    )
+  // Provide a default implementation for the search context mock
+  beforeEach(() => {
+    useSearchContext.mockImplementation(() => ({
+        ...jest.requireActual('../SearchContext').useSearchContext(),
+        useAgg: (quantity, visible, id, config) => {
+          return useMemo(() => {
+            return visible
+              ? {data: [{value: 'H', count: 123}]}
+              : undefined
+          }, [visible])
+        },
+        useFilterState: (quantity) => {
+          const response = useMemo(() => {
+            return [undefined, mockSetFilter]
+          }, [])
+          return response
+        }
+    }))
   })
-  afterEach(() => closeAPI())
 
-  test('initial state is loaded correctly', async () => {
-    await expectPeriodicTable(quantity, false, ['H', 'C', 'N', 'I', 'Pb', 'Ti', 'Zr', 'Nb', 'Hf', 'Ta'])
+  describe('test showHeader', () => {
+    test.each([
+      ['show header', {showHeader: true}],
+      ['do not show header', {showHeader: false}]
+    ])('%s', async (name, config) => {
+      renderPeriodicTable(config, new Filter(undefined, {quantity: 'test'}))
+      if (config.showHeader) {
+        expect(screen.getByText('Test')).toBeInTheDocument()
+      } else {
+        expect(screen.queryByText('Test')).not.toBeInTheDocument()
+      }
+    })
   })
-})
 
-describe('', () => {
-  beforeEach(async () => {
-    await startAPI(stateName, 'tests/data/search/inputperiodictable-edit')
-    renderSearchEntry(<InputPeriodicTable
-      quantity={quantity}
-      visible
-    />
-    )
+  describe('test title', () => {
+    test.each([
+      ['default title', {}, 'Test'],
+      ['custom title', {title: 'Custom title'}, 'Custom title']
+    ])('%s', async (name, config, expected) => {
+      renderPeriodicTable(config, new Filter(undefined, {quantity: 'test'}))
+      expect(screen.getByText(expected)).toBeInTheDocument()
+    })
   })
-  afterEach(() => closeAPI())
 
-  test('selecting an element in both non-exclusive and exclusive mode correctly updates the table', async () => {
-    // Wait for hydrogen to become selectable
-    await waitFor(() => expectElement('Hydrogen', false))
+  describe('test showStatistics', () => {
+    test.each([
+      ['show statistics', {showStatistics: true}],
+      ['do not show statistics', {showStatistics: false}]
+    ])('%s', async (name, config) => {
+      renderPeriodicTable(config, new Filter(undefined, {quantity: 'test'}))
 
-    // Test that after selecting C, only the correct elements are selectable.
-    const cButton = screen.getByTestId('Carbon')
-    await userEvent.click(cButton)
-    await expectPeriodicTableItems(['H', 'C', 'N', 'I', 'Pb'])
+      const option = screen.queryAllByText('123')
+      const scaling = screen.queryByText('linear')
+      if (config.showStatistics) {
+        expect(option).toHaveLength(1)
+        expect(scaling).toBeInTheDocument()
+      } else {
+        expect(option).toHaveLength(0)
+        expect(scaling).not.toBeInTheDocument()
+      }
+    })
+  })
+
+  describe('test selection', () => {
+    test.each([
+      ['show statistics', {showStatistics: true}],
+      ['do not show statistics', {showStatistics: false}]
+    ])('%s', async (name, config) => {
+      renderPeriodicTable(config, new Filter(undefined, {quantity: 'test'}))
 
-    // Test that after enabling exclusive search, only C is selectable
-    const exclusiveCheckbox = screen.getByRole('checkbox')
-    await userEvent.click(exclusiveCheckbox)
-    await expectPeriodicTableItems(['C'])
+      // Click on hydrogen
+      const cButton = screen.getByTestId('Hydrogen')
+      await userEvent.click(cButton)
+
+      // setFilter is called
+      expect(mockSetFilter.mock.calls).toHaveLength(1)
+      const argument = mockSetFilter.mock.calls[0][0]()
+      const expectedArgument = new Set(['H'])
+      expect(argument.size === expectedArgument.size).toBe(true)
+      expect([...argument].every((x) => expectedArgument.has(x))).toBe(true)
+    })
   })
 })
+
+// Helper function for rendering
+function renderPeriodicTable(config, filter) {
+  const searchQuantities = {test: filter}
+  render(
+    <SearchContextRaw
+      resource="entries"
+      id='entries'
+      initialSearchQuantities={searchQuantities}
+    >
+      <InputPeriodicTable visible searchQuantity={filter.quantity} {...config}/>
+    </SearchContextRaw>
+  )
+}
diff --git a/gui/src/components/search/input/InputRange.spec.js b/gui/src/components/search/input/InputRange.spec.js
deleted file mode 100644
index b5da2751d8..0000000000
--- a/gui/src/components/search/input/InputRange.spec.js
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright The NOMAD Authors.
- *
- * This file is part of NOMAD. See https://nomad-lab.eu for further info.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React from 'react'
-import { fireEvent } from '@testing-library/dom'
-import userEvent from '@testing-library/user-event'
-import { format } from 'date-fns'
-import { startAPI, closeAPI, screen } from '../../conftest.spec'
-import { renderSearchEntry, expectInputRange } from '../conftest.spec'
-import InputRange from './InputRange'
-import { defaultFilterData } from '../FilterRegistry'
-import { DType, formatNumber } from '../../../utils'
-
-const nBins = 30
-const stateName = 'tests.states.search.histograms'
-const discrete = ['results.material.n_elements', false, 1, 5, 1]
-const discrete_histogram = ['results.material.n_elements', true, 1, 5, 1]
-const continuous = ['results.properties.electronic.band_structure_electronic.band_gap.value', false, 0, 2, 0.1]
-const continuous_histogram = ['results.properties.electronic.band_structure_electronic.band_gap.value', true, 0, 2, 2 / nBins]
-const time = ['upload_create_time', false, 1585872000000, 1585872240000, (1585872240000 - 1585872000000) / nBins]
-const time_histogram = ['upload_create_time', true, 1585872000000, 1585872240000, undefined]
-
-describe('test initial state', () => {
-  beforeAll(async () => { await startAPI(stateName, 'tests/data/search/inputrange-init') })
-  afterAll(() => closeAPI())
-
-  test.each([
-    continuous,
-    continuous_histogram,
-    discrete,
-    discrete_histogram,
-    time,
-    time_histogram
-  ])('quantity: %s, histogram: %s', async (quantity, histogram, min, max) => {
-    renderSearchEntry(<InputRange visible quantity={quantity} disableHistogram={!histogram}/>)
-    await expectInputRange({x: {quantity}}, false, histogram, false, min, max)
-  })
-})
-
-describe('test invalid/valid numeric input', () => {
-  beforeAll(async () => { await startAPI(stateName, 'tests/data/search/inputrange-validation') })
-  afterAll(() => closeAPI())
-  const [quantity, histogram, min, max] = discrete
-
-  for (const isMin of [false, true]) {
-    const value = isMin ? min : max
-    const field = isMin ? 'minimum' : 'maximum'
-    const message = `Invalid ${field} value.`
-    test.each([
-      ['1', true],
-      ['1.0', true],
-      ['-1.0', true],
-      ['-1.0e5', true],
-      ['-1.0e-5', true],
-      ['hello', false],
-      [' ', false]
-    ])(
-      `field: ${field}, input: %s, valid: %s`,
-      async (input, valid) => {
-        renderSearchEntry(<InputRange visible quantity={quantity} disableHistogram={!histogram}/>)
-        const user = userEvent.setup()
-        const field = await screen.findByDisplayValue(value)
-        await user.clear(field)
-        await user.type(field, input)
-        await user.keyboard('[Enter]')
-        if (valid) {
-          expect(screen.queryByText(message)).toBeNull()
-        } else {
-          expect(screen.queryByText(message)).toBeInTheDocument()
-        }
-      }
-    )
-  }
-})
-
-describe('test histograms with only one value', () => {
-  beforeAll(async () => {
-    await startAPI(
-      'tests.states.search.histograms_one_value',
-      'tests/data/search/inputrange-one-value'
-    )
-  })
-  afterAll(() => closeAPI())
-
-  test.each([
-    ['results.material.n_elements', 1],
-    ['results.properties.electronic.band_structure_electronic.band_gap.value', 0.5],
-    ['upload_create_time', 1585872000000]
-  ])('quantity: %s', async (quantity, value) => {
-    renderSearchEntry(<InputRange visible quantity={quantity} disableHistogram={false}/>)
-    const data = defaultFilterData[quantity]
-    const dtype = data.dtype
-
-    // Check that both text fields show the only available value
-    const inputValue = dtype === DType.Timestamp
-      ? format(value, 'dd/MM/yyyy kk:mm')
-      : value
-    const inputs = await screen.findAllByDisplayValue(inputValue)
-    expect(inputs.length).toBe(2)
-
-    // Check that slider is disabled: trying to modify the sliders does not
-    // update the input fields.
-    const sliders = screen.getAllByRole('slider')
-    const sliderMin = sliders[0]
-    const sliderMax = sliders[1]
-    fireEvent.keyDown(sliderMin, {key: 'Up', code: 'Up'})
-    fireEvent.keyDown(sliderMax, {key: 'Down', code: 'Down'})
-    const inputsNew = await screen.findAllByDisplayValue(inputValue)
-    expect(inputsNew.length).toBe(2)
-  })
-})
-
-test.each([
-  discrete,
-  discrete_histogram,
-  continuous,
-  continuous_histogram
-])('inputs react to slider change: quantity: %s, histogram: %s', async (quantity, histogram, min, max, step) => {
-  await startAPI(stateName, `tests/data/search/inputrange-${quantity}-${histogram}-slider-change`)
-  renderSearchEntry(<InputRange visible quantity={quantity} disableHistogram={!histogram}/>)
-  const inputMin = await screen.findByDisplayValue(min)
-  const inputMax = await screen.findByDisplayValue(max)
-  const sliders = screen.getAllByRole('slider')
-  const sliderMin = sliders[0]
-  const sliderMax = sliders[1]
-
-  // Moving min slider changes min field
-  fireEvent.keyDown(sliderMin, {key: 'Up', code: 'Up'})
-  expect(inputMin.value).toBe(formatNumber(min + step))
-
-  // Moving max slider changes max field
-  fireEvent.keyDown(sliderMax, {key: 'Down', code: 'Down'})
-  expect(inputMax.value).toBe(formatNumber(max - step))
-  closeAPI()
-})
-
-test.each([
-  continuous,
-  continuous_histogram,
-  discrete,
-  discrete_histogram
-])('sliders react to input field change: quantity: %s, histogram: %s', async (quantity, histogram, min, max) => {
-  await startAPI(stateName, `tests/data/search/inputrange-${quantity}-${histogram}-input-change`)
-  renderSearchEntry(<InputRange visible quantity={quantity} disableHistogram={!histogram}/>)
-  const inputMin = await screen.findByDisplayValue(min)
-  const inputMax = await screen.findByDisplayValue(max)
-  const sliders = screen.getAllByRole('slider')
-  const sliderMin = sliders[0]
-  const sliderMax = sliders[1]
-
-  // Initially both sliders at the ends
-  expect(sliderMin).toHaveStyle(`left: 0%`)
-  expect(sliderMax).toHaveStyle(`left: 100%`)
-
-  // After changing the min field to 25%, min slider moves to 25% position.
-  await testSliderMove(quantity, min, max, inputMin, sliderMin, 25, false, histogram)
-
-  // After changing the max field to 75%, min slider moves to 75% position.
-  await testSliderMove(quantity, min, max, inputMax, sliderMax, 75, true, histogram)
-  closeAPI()
-})
-
-/**
- * Tests that a slider moves to the given location when text input changes.
- * @param {string} quantity The quantity name
- * @param {number} min Minimum value of the slider
- * @param {number} max Maximum value of the slider
- * @param {*} input Text input element
- * @param {*} slider MUI slider knob element
- * @param {number} percentage The percentage to move to.
- * @param {bool} isMax Is the max knob being moved.
- * @param {bool} isMax Is the slider shown for a histogram.
- */
-async function testSliderMove(quantity, min, max, input, slider, percentage, isMax, histogram) {
-  const data = defaultFilterData[quantity]
-  const dtype = data.dtype
-  const discretization = (histogram && dtype === DType.Int) ? 1 : 0
-  const range = max - min + discretization
-  const value = min + range * (percentage / 100) - (isMax ? discretization : 0)
-
-  const user = userEvent.setup()
-  await user.clear(input)
-  await user.type(input, value.toString())
-  await user.keyboard('[Enter]')
-
-  const style = window.getComputedStyle(slider)
-  const left = parseFloat(style.getPropertyValue('left').slice(0, -1))
-  expect(left).toBeCloseTo(percentage, 8)
-}
diff --git a/gui/src/components/search/input/InputField.js b/gui/src/components/search/input/InputTerms.js
similarity index 61%
rename from gui/src/components/search/input/InputField.js
rename to gui/src/components/search/input/InputTerms.js
index f3bbb19c19..199e5dbf89 100644
--- a/gui/src/components/search/input/InputField.js
+++ b/gui/src/components/search/input/InputTerms.js
@@ -17,6 +17,7 @@
  */
 import React, { useCallback, useEffect, useState, useMemo } from 'react'
 import { makeStyles, useTheme } from '@material-ui/core/styles'
+import { Box } from '@material-ui/core'
 import PropTypes from 'prop-types'
 import clsx from 'clsx'
 import { useRecoilValue } from 'recoil'
@@ -25,9 +26,8 @@ import InputTooltip from './InputTooltip'
 import InputItem, { inputItemHeight } from './InputItem'
 import InputUnavailable from './InputUnavailable'
 import Placeholder from '../../visualization/Placeholder'
-import { formatLabel } from '../../../utils'
 import { useSearchContext } from '../SearchContext'
-import { isNil } from 'lodash'
+import { isNil, isNumber } from 'lodash'
 import Pagination from '../../visualization/Pagination'
 import { guiState } from '../../GUIMenu'
 import { InputTextQuantity } from './InputText'
@@ -48,7 +48,8 @@ const useStyles = makeStyles(theme => ({
     alignItems: 'flex-start',
     justifyContent: 'center',
     flexDirection: 'column',
-    boxSizing: 'border-box'
+    boxSizing: 'border-box',
+    marginBottom: theme.spacing(-0.5)
   },
   container: {
     width: '100%'
@@ -65,20 +66,20 @@ const useStyles = makeStyles(theme => ({
     marginBottom: theme.spacing(1)
   }
 }))
-const InputField = React.memo(({
-  quantity,
-  label,
+const InputTerms = React.memo(({
+  searchQuantity,
+  title,
   description,
   visible,
-  xs,
-  initialScale,
-  initialSize,
+  nColumns,
+  scale,
   increment,
-  disableStatistics,
-  disableSearch,
-  disableOptions,
-  disableSuggestions,
-  formatLabels,
+  showInput,
+  showHeader,
+  showStatistics,
+  showSuggestions,
+  options,
+  sortStatic,
   className,
   classes,
   'data-testid': testID
@@ -96,84 +97,94 @@ const InputField = React.memo(({
   const [visibleOptions, setVisibleOptions] = useState()
   const aggIndicator = useRecoilValue(guiState('aggIndicator'))
   const aggCollapse = useRecoilValue(guiState('aggCollapse'))
-  const [scale, setScale] = useState(initialScale || filterData[quantity]?.scale || 'linear')
-  disableStatistics = isNil(disableStatistics) ? !isStatisticsEnabled : disableStatistics
+  const [scaleState, setScaleState] = useState(scale || filterData[searchQuantity]?.scale || 'linear')
+  showStatistics = isStatisticsEnabled && showStatistics
+  const nOptions = isNumber(options) ? options : undefined
 
   // See if the filter has a fixed amount of options. These may have been
-  // explicitly provided or defined in the metainfo. If you explicitly specify
-  // an initialSize, any fixed options are ignored and the data is retrieved
-  // through an aggregation (this is done because the top aggregations may not
-  // match the list of explicit options).
-  const fixedOptions = useMemo(() => {
-    return isNil(initialSize)
-      ? filterData[quantity]?.options
+  // explicitly provided or defined in the metainfo. If options is given as a
+  // number, any fixed options are ignored and the data is retrieved through an
+  // aggregation.
+  const fixedOptions = useMemo(() => isNil(nOptions)
+      ? options || filterData[searchQuantity]?.options
       : undefined
-  }, [initialSize, filterData, quantity])
+  , [nOptions, filterData, searchQuantity, options])
+
   const nFixedOptions = fixedOptions && Object.keys(fixedOptions).length
-  const minSize = disableOptions ? 0 : initialSize || nFixedOptions || filterData[quantity]?.aggs?.terms?.size
-  const placeholder = filterData[quantity]?.placeholder || "Type here"
+  const minSize = nOptions === 0
+    ? 0
+    : nOptions || nFixedOptions || filterData[searchQuantity]?.aggs?.terms?.size || 5
+  const placeholder = filterData[searchQuantity]?.placeholder || "Type here"
   const [requestedAggSize, setRequestedAggSize] = useState(minSize)
   const incr = useState(increment || minSize)[0]
   const [loading, setLoading] = useState(false)
+
+  // If a fixed list of options is used, we must restrict the aggregation return
+  // values with 'include'. Otherwise the returned results may contain other
+  // values.
   const aggConfig = useMemo(() => {
     const config = {type: 'terms', size: minSize}
-    // If a fixed list of options is used, we must restrict the aggregation
-    // return values with 'include'. Otherwise the returned results may not
-    // contain the correct values.
-    const options = filterData[quantity]?.options
-    if (options) config.include = Object.keys(options)
+    if (fixedOptions) config.include = Object.keys(fixedOptions)
     return config
-  }, [minSize, filterData, quantity])
-  const agg = useAgg(quantity, visible && !disableOptions && !(disableStatistics && fixedOptions), 'scroll', aggConfig)
-  const aggCall = useAggCall(quantity, 'scroll')
+  }, [minSize, fixedOptions])
+
+  const agg = useAgg(searchQuantity, visible && !(nOptions === 0) && !(!showStatistics && fixedOptions), 'scroll', aggConfig)
+  const aggCall = useAggCall(searchQuantity, 'scroll')
   const receivedAggSize = agg?.data?.length
-  const [filter, setFilter] = useFilterState(quantity)
-  const unavailable = disableOptions ? false : !(agg?.data && agg.data.length > 0)
+  const [filter, setFilter] = useFilterState(searchQuantity)
+  const unavailable = (nOptions === 0) ? false : !(agg?.data && agg.data.length > 0)
   const disabled = unavailable
 
   // Form the final list of options. If no fixed options are available, the
   // options are gathered from the aggregation.
   const finalOptions = useMemo(() => {
-    if (fixedOptions) {
-      return fixedOptions
-    }
-    if (agg?.data) {
-      const opt = {}
-      const maxSize = Math.min(requestedAggSize, agg.data.length)
-      for (let i = 0; i < maxSize; ++i) {
-        const value = agg.data[i]
-        opt[value.value] = {label: value.value}
-      }
+    if (fixedOptions) return fixedOptions
+    if (!agg?.data) return {}
+
+    const maxSize = Math.min(requestedAggSize, agg.data.length)
+    return agg.data.slice(0, maxSize).reduce((opt, { value }) => {
+      opt[value] = { label: value }
       return opt
-    }
-    return {}
+    }, {})
   }, [fixedOptions, agg, requestedAggSize])
 
   // Modify the checkboxes according to changing filters, changing aggregation
   // results or change in the available options.
   useEffect(() => {
-    const opt = {}
-    for (const [key, value] of Object.entries(finalOptions)) {
+    let options = Object.entries(finalOptions).reduce((opt, [key, value]) => {
+      const selected = filter?.has(key) || false
       opt[key] = {
-        checked: filter ? filter.has(key) : false,
-        label: formatLabels ? formatLabel(value.label) : value.label,
-        disabled: !disableStatistics
+        checked: selected,
+        label: value.label,
+        disabled: isStatisticsEnabled && showStatistics && !selected
       }
-    }
+      return opt
+    }, {})
+
     if (agg?.data) {
-      for (const value of agg.data) {
-        const key = value.value
-        const selected = filter ? filter.has(key) : false
-        const oldState = opt[key]
-        const disabled = selected ? false : value.count === 0
-        if (oldState) {
-          oldState.count = value.count
-          oldState.disabled = disabled
+      // Update counts and disable if not selected and count is 0
+      agg.data?.forEach(({ value, nested_count }) => {
+        const selected = filter?.has(value) || false
+        if (options[value]) {
+          options[value].nested_count = nested_count
+          options[value].disabled = selected ? false : nested_count === 0
         }
+      })
+
+      // Sort by count if using fixed options and sorting is enabled
+      if (fixedOptions && sortStatic) {
+        options = Object.fromEntries(
+          Object.entries(options).sort(([, a], [, b]) => {
+            const bCount = b.nested_count || 0
+            const aCount = a.nested_count || 0
+            return bCount - aCount
+          })
+        )
       }
     }
-    setVisibleOptions(opt)
-  }, [agg, filter, finalOptions, disableStatistics, formatLabels])
+
+    setVisibleOptions(options)
+  }, [agg?.data, filter, finalOptions, fixedOptions, isStatisticsEnabled, showStatistics, sortStatic])
 
   // Show more values
   const handleShowMore = useCallback(() => {
@@ -209,25 +220,25 @@ const InputField = React.memo(({
 
   // Create the search component
   const searchComponent = useMemo(() => {
-    return disableSearch
-      ? null
-      : <InputTooltip unavailable={unavailable}>
+    return showInput
+      ? <InputTooltip unavailable={unavailable}>
         <div className={styles.container}>
           <InputTextQuantity
             className={styles.textField}
-            quantity={quantity}
+            quantity={searchQuantity}
             disabled={disabled}
-            disableSuggestions={disableSuggestions}
+            disableSuggestions={!showSuggestions}
             placeholder={placeholder}
             fullWidth
           />
         </div>
       </InputTooltip>
-  }, [disableSearch, unavailable, styles, quantity, disabled, disableSuggestions, placeholder])
+      : null
+  }, [showInput, unavailable, styles, searchQuantity, disabled, showSuggestions, placeholder])
 
   // Create the options component
   const optionsComponent = useMemo(() => {
-    if (disableOptions) {
+    if ((nOptions === 0)) {
       return
     }
 
@@ -242,6 +253,7 @@ const InputField = React.memo(({
       ? false
       : (requestedAggSize - incr >= minSize)
 
+    const xs = 12 / nColumns
     const nRows = Math.ceil(nItems * xs / 12)
     const actionsHeight = 34
     let reservedHeight
@@ -251,12 +263,12 @@ const InputField = React.memo(({
       reservedHeight = nItems > 0 ? (itemHeight + actionHeight) : undefined
     } else if (aggCollapse === 'off') {
       const itemHeight = Math.max(minSize * xs / 12, nRows) * inputItemHeight
-      const allLoaded = !isNil(nFixedOptions) && initialSize >= nFixedOptions
+      const allLoaded = !isNil(nFixedOptions) && nOptions >= nFixedOptions
       const actionHeight = (fixedOptions || allLoaded) ? 0 : actionsHeight
       reservedHeight = itemHeight + actionHeight
     }
 
-    const max = agg ? Math.max(...agg.data.map(option => option.count)) : 0
+    const max = agg ? Math.max(...agg.data.map(option => option.nested_count)) : 0
     const items = visibleOptions && <div
       className={styles.grid}
       style={{gridTemplateRows: `repeat(${nRows}, 1fr)`}}
@@ -265,25 +277,31 @@ const InputField = React.memo(({
         <InputItem
           key={key}
           value={key}
+          tooltip={value.description}
           label={value.label}
           selected={value.checked}
           disabled={value.disabled}
-          disableStatistics={disableStatistics}
+          disableStatistics={!showStatistics}
           onChange={handleChange}
           variant="checkbox"
           max={max}
-          count={value.count}
-          scale={scale}
+          count={value.nested_count}
+          scale={scaleState}
         />
       ))}
     </div>
 
     const noMore = agg?.exhausted && receivedAggSize === requestedAggSize
     let aggComp
-    if (fixedOptions) {
+
+    // If statistics are disabled and there is a fixed number of options, we
+    // show the options immediately.
+    if ((!showStatistics || !sortStatic) && fixedOptions) {
       aggComp = items
-    } else if (receivedAggSize === 0) {
+    // No fixed options or aggregation data is available
+    } else if (receivedAggSize === 0 && !fixedOptions) {
       aggComp = <InputUnavailable/>
+    // Show placeholder if aggregation is underway
     } else if (!agg && aggIndicator === 'on') {
       aggComp = <Placeholder
         variant="rect"
@@ -308,8 +326,7 @@ const InputField = React.memo(({
       {aggComp}
     </div>
   }, [
-    disableOptions,
-    disableStatistics,
+    showStatistics,
     agg,
     finalOptions,
     minSize,
@@ -317,57 +334,65 @@ const InputField = React.memo(({
     receivedAggSize,
     requestedAggSize,
     incr,
-    xs,
+    nColumns,
     aggCollapse,
     visibleOptions,
     styles,
     aggIndicator,
-    initialSize,
     handleChange,
-    scale,
+    scaleState,
     handleShowMore,
     handleShowLess,
     loading,
     nFixedOptions,
-    testID
-  ]
-  )
+    testID,
+    nOptions,
+    sortStatic
+  ])
 
   return <div className={clsx(className, styles.root)} data-testid={testID}>
-    <InputHeader
-      quantity={quantity}
-      label={label}
-      description={description}
-      scale={scale}
-      onChangeScale={setScale}
-      disableStatistics={disableStatistics}
-    />
+    {showHeader
+      ? <InputHeader
+        quantity={searchQuantity}
+        label={title}
+        description={description}
+        scale={scaleState}
+        onChangeScale={setScaleState}
+        disableStatistics={!showStatistics}
+      />
+      : <Box marginBottom={0.5}/>
+    }
     {searchComponent}
     {optionsComponent}
   </div>
 })
 
-InputField.propTypes = {
-  quantity: PropTypes.string.isRequired,
-  label: PropTypes.string,
+InputTerms.propTypes = {
+  searchQuantity: PropTypes.string.isRequired,
+  title: PropTypes.string,
   description: PropTypes.string,
   visible: PropTypes.bool,
-  xs: PropTypes.number,
-  initialScale: PropTypes.number, // The initial statistics scaling
-  initialSize: PropTypes.number, // The initial maximum number of items to load
+  nColumns: PropTypes.number, // Number of columns to use
+  scale: PropTypes.string, // The statistics scaling
+  options: PropTypes.oneOfType([PropTypes.number, PropTypes.object]), // Controls what options to show
+  sortStatic: PropTypes.bool, // Whether to sort statically defined options by occurrence
   increment: PropTypes.number, // The amount of new items to load on 'show more'
-  disableStatistics: PropTypes.bool, // Whether to disable statistics
-  disableSearch: PropTypes.bool, // Whether to show the search field
-  disableOptions: PropTypes.bool, // Whether to show the options gathered through aggregations
-  disableSuggestions: PropTypes.bool, // Whether to disable the text field suggestions
-  formatLabels: PropTypes.bool, // Whether to reformat the options labels
+  showInput: PropTypes.bool, // Whether to show the search input field
+  showHeader: PropTypes.bool, // Whether to show the header
+  showStatistics: PropTypes.bool, // Whether to disable statistics
+  showSuggestions: PropTypes.bool, // Whether to disable the text field suggestions
   className: PropTypes.string,
   classes: PropTypes.object,
   'data-testid': PropTypes.string
 }
 
-InputField.defaultProps = {
-  xs: 12
+InputTerms.defaultProps = {
+  nColumns: 1,
+  showHeader: true,
+  showInput: true,
+  showStatistics: true,
+  sortStatic: true,
+  'data-testid': 'input-terms'
 }
 
-export default InputField
+export default InputTerms
diff --git a/gui/src/components/search/input/InputTerms.spec.js b/gui/src/components/search/input/InputTerms.spec.js
new file mode 100644
index 0000000000..cffd755969
--- /dev/null
+++ b/gui/src/components/search/input/InputTerms.spec.js
@@ -0,0 +1,209 @@
+/*
+ * Copyright The NOMAD Authors.
+ *
+ * This file is part of NOMAD. See https://nomad-lab.eu for further info.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React, { useMemo } from 'react'
+import { waitFor, within } from '@testing-library/dom'
+import { render, screen } from '../../conftest.spec'
+import { expectInputItem } from '../conftest.spec'
+import { SearchContextRaw } from '../SearchContext'
+import { Filter } from '../Filter'
+import { isNumber } from 'lodash'
+import InputTerms from './InputTerms'
+import userEvent from '@testing-library/user-event'
+
+// Use a mocked SearchContext
+const mockSetFilter = jest.fn()
+const mockUseMemo = useMemo
+jest.mock('../SearchContext', () => ({
+    ...jest.requireActual('../SearchContext'),
+    useSearchContext: () => ({
+      ...jest.requireActual('../SearchContext').useSearchContext(),
+      useAgg: (quantity, visible, id, config) => {
+        const response = mockUseMemo(() => {
+          return visible
+            ? {data: [
+              {value: 'A', count: 6},
+              {value: 'B', count: 5},
+              {value: 'C', count: 4},
+              {value: 'D', count: 3},
+              {value: 'E', count: 2},
+              {value: 'F', count: 1}
+            ].slice(0, config.size)}
+            : undefined
+        }, [])
+        return response
+      },
+      useFilterState: jest.fn((quantity) => {
+        const response = mockUseMemo(() => {
+          return [undefined, mockSetFilter]
+        }, [])
+        return response
+      })
+    })
+}))
+
+describe('test options', () => {
+  test.each([
+    [
+      'show all options for enum by default',
+      {options: undefined},
+      new Filter(undefined, {quantity: 'test', options: {A: {label: 'A'}, B: {label: 'B'}}}),
+      [{label: 'A'}, {label: 'B'}]
+    ],
+    [
+      'show 5 options for str by default',
+      {options: undefined},
+      new Filter(undefined, {quantity: 'test'}),
+      [{label: 'A'}, {label: 'B'}, {label: 'C'}, {label: 'D'}, {label: 'E'}]
+    ],
+    [
+      'no options',
+      {options: 0},
+      new Filter(undefined, {quantity: 'test'}),
+      []
+    ],
+    [
+      'limited options',
+      {options: 2},
+      new Filter(undefined, {quantity: 'test'}),
+      [{label: 'A'}, {label: 'B'}]
+    ],
+    [
+      'custom options',
+      {options: {B: {label: 'B'}}},
+      new Filter(undefined, {quantity: 'test', options: {A: {label: 'A'}, B: {label: 'B'}}}),
+      [{label: 'B'}]
+    ]
+  ])('%s', async (name, config, filter, expected) => {
+    renderInputTerms(config, filter)
+
+    // Wait for possible placeholder to disappear
+    await waitFor(() => expect(screen.queryByTestId(`input-terms-placeholder`)).toBe(null))
+
+    // Check that each expected item appears
+    expect(screen.queryAllByRole('checkbox').length).toBe(expected.length)
+    for (const item of expected) {
+      expectInputItem(item)
+    }
+
+    // When getting options dynamically, test that the "show more" button is
+    // shown, but "show less" is not shown
+    if (isNumber(config.options) && config.options > 0) {
+      expect(screen.getByText('Show more')).toBeInTheDocument()
+      expect(screen.queryByText('Show less')).not.toBeInTheDocument()
+    }
+  })
+})
+
+describe('test showHeader', () => {
+  test.each([
+    ['show header', {showHeader: true}],
+    ['do not show header', {showHeader: false}]
+  ])('%s', async (name, config) => {
+    renderInputTerms(config, new Filter(undefined, {quantity: 'test'}))
+    if (config.showHeader) {
+      expect(screen.getByText('Test')).toBeInTheDocument()
+    } else {
+      expect(screen.queryByText('Test')).not.toBeInTheDocument()
+    }
+  })
+})
+
+describe('test title', () => {
+  test.each([
+    ['default title', {}, 'Test'],
+    ['custom title', {title: 'Custom title'}, 'Custom title']
+  ])('%s', async (name, config, expected) => {
+    renderInputTerms(config, new Filter(undefined, {quantity: 'test'}))
+    expect(screen.getByText(expected)).toBeInTheDocument()
+  })
+})
+
+describe('test showStatistics', () => {
+  test.each([
+    ['show statistics', {showStatistics: true}],
+    ['do not show statistics', {showStatistics: false}]
+  ])('%s', async (name, config) => {
+    renderInputTerms(config, new Filter(undefined, {quantity: 'test'}))
+    const option = screen.queryByText('6')
+    const scaling = screen.queryByText('linear')
+    if (config.showStatistics) {
+      expect(option).toBeInTheDocument()
+      expect(scaling).toBeInTheDocument()
+    } else {
+      expect(option).not.toBeInTheDocument()
+      expect(scaling).not.toBeInTheDocument()
+    }
+  })
+})
+
+describe('test showInput', () => {
+  test.each([
+    ['show input', {showInput: true}],
+    ['do not show input', {showInput: false}]
+  ])('%s', async (name, config) => {
+    renderInputTerms(config, new Filter(undefined, {quantity: 'test'}))
+    if (config.showInput) {
+      expect(screen.getByPlaceholderText('Type here')).toBeInTheDocument()
+    } else {
+      expect(screen.queryByPlaceholderText('Type here')).not.toBeInTheDocument()
+    }
+  })
+})
+
+test.only('test item selection', async () => {
+  renderInputTerms({}, new Filter(undefined, {quantity: 'test'}))
+
+  // Wait for possible placeholder to disappear
+  await waitFor(() => expect(screen.queryByTestId(`input-terms-placeholder`)).toBe(null))
+
+  // Select one item
+  const checkbox = queryByInputItemName('A')
+  await userEvent.click(checkbox)
+
+  // Check that the setFilter function is called once with the correct argument
+  expect(mockSetFilter.mock.calls).toHaveLength(1)
+  const argument = mockSetFilter.mock.calls[0][0]
+  const expectedArgument = new Set(['A'])
+  expect(argument.size === expectedArgument.size).toBe(true)
+  expect([...argument].every((x) => expectedArgument.has(x))).toBe(true)
+})
+
+// Helper function for rendering
+function renderInputTerms(config, filter) {
+  const searchQuantities = {test: filter}
+  render(
+    <SearchContextRaw
+      resource="entries"
+      id='entries'
+      initialSearchQuantities={searchQuantities}
+    >
+      <InputTerms visible searchQuantity={filter.quantity} {...config}/>
+    </SearchContextRaw>
+  )
+}
+
+/**
+ * Finds the checkbox corresponding to an InputItem with the given value.
+ * @param {string} name The option value that is displayed
+ * @returns {element} The checkbox input HTML element.
+ */
+function queryByInputItemName(option, root = screen) {
+  const inputLabel = root.queryByText(option)
+  const inputCheckbox = inputLabel && within(inputLabel.closest('label')).getByRole('checkbox')
+  return inputCheckbox
+}
diff --git a/gui/src/components/search/input/InputVisibility.js b/gui/src/components/search/input/InputVisibility.js
new file mode 100644
index 0000000000..a7efda6881
--- /dev/null
+++ b/gui/src/components/search/input/InputVisibility.js
@@ -0,0 +1,43 @@
+/*
+ * Copyright The NOMAD Authors.
+ *
+ * This file is part of NOMAD. See https://nomad-lab.eu for further info.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react'
+import InputRadio from './InputRadio'
+import { useApi } from '../../api'
+
+const InputVisibility = React.memo(() => {
+  const {api} = useApi()
+  const authenticated = api?.keycloak?.authenticated
+
+  return <InputRadio
+      quantity="visibility"
+      label="Visibility"
+      initialValue={authenticated ? 'visible' : 'public'}
+      options={{
+        all: {label: 'All', disabled: !authenticated, tooltip: 'Consider all entries.'},
+        public: {label: 'Public', disabled: false, tooltip: 'Consider all entries that can be publically downloaded, i.e. only published entries without embargo.'},
+        visible: {label: 'Visible', disabled: !authenticated, tooltip: 'Consider all entries that are visible to you. This includes entries with embargo or unpublished entries that belong to you or are shared with you.'},
+        shared: {label: 'Shared', disabled: !authenticated, tooltip: 'Only consider entries that belong to you or are shared with you.'},
+        user: {label: 'User', disabled: !authenticated, tooltip: 'Only consider entries that belong to you.'},
+        staging: {label: 'Unpublished', disabled: !authenticated, tooltip: 'Only search through unpublished entries.'}
+      }}
+    />
+})
+
+InputVisibility.propTypes = {}
+
+export default InputVisibility
diff --git a/gui/src/components/search/menus/FilterMainMenu.js b/gui/src/components/search/menus/FilterMainMenu.js
deleted file mode 100644
index 37ce4f8544..0000000000
--- a/gui/src/components/search/menus/FilterMainMenu.js
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright The NOMAD Authors.
- *
- * This file is part of NOMAD. See https://nomad-lab.eu for further info.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React, { useEffect, useMemo, useState } from 'react'
-import PropTypes from 'prop-types'
-import { Alert } from '@material-ui/lab'
-import { has } from 'lodash'
-import {
-  FilterMenu,
-  FilterMenuItem,
-  FilterMenuItems,
-  FilterSubMenus
-} from './FilterMenu'
-import { makeStyles } from '@material-ui/core/styles'
-import FilterSubMenuElements from './FilterSubMenuElements'
-import FilterSubMenuStructure from './FilterSubMenuStructure'
-import FilterSubMenuMethod from './FilterSubMenuMethod'
-import FilterSubMenuPrecision from './FilterSubMenuPrecision'
-import FilterSubMenuDFT from './FilterSubMenuDFT'
-import FilterSubMenuTB from './FilterSubMenuTB'
-import FilterSubMenuGW from './FilterSubMenuGW'
-import FilterSubMenuBSE from './FilterSubMenuBSE'
-import FilterSubMenuDMFT from './FilterSubMenuDMFT'
-import FilterSubMenuEELS from './FilterSubMenuEELS'
-import FilterSubMenuElectronic from './FilterSubMenuElectronic'
-import FilterSubMenuSolarCell from './FilterSubMenuSolarCell'
-import FilterSubMenuCatalyst from './FilterSubMenuCatalystProperties'
-import FilterSubMenuVibrational from './FilterSubMenuVibrational'
-import FilterSubMenuMechanical from './FilterSubMenuMechanical'
-import FilterSubMenuMolecularDynamics from './FilterSubMenuMolecularDynamics'
-import FilterSubMenuELN from './FilterSubMenuELN'
-import FilterSubMenuAuthor from './FilterSubMenuAuthor'
-import FilterSubMenuMetadata from './FilterSubMenuMetadata'
-import FilterSubMenuOptimade from './FilterSubMenuOptimade'
-import { useSearchContext } from '../SearchContext'
-import { delay } from '../../../utils'
-import FilterSubMenuGeometryOptimization from './FilterSubMenuGeometryOptimization'
-import InputCheckbox from '../input/InputCheckbox'
-import FilterSubMenuCustomQuantities from './FilterSubMenuCustomQuantities'
-
-export const menuMap = {
-  elements: FilterSubMenuElements,
-  structure: FilterSubMenuStructure,
-  method: FilterSubMenuMethod,
-  precision: FilterSubMenuPrecision,
-  dft: FilterSubMenuDFT,
-  tb: FilterSubMenuTB,
-  gw: FilterSubMenuGW,
-  bse: FilterSubMenuBSE,
-  dmft: FilterSubMenuDMFT,
-  eels: FilterSubMenuEELS,
-  electronic: FilterSubMenuElectronic,
-  solarcell: FilterSubMenuSolarCell,
-  heterogeneouscatalyst: FilterSubMenuCatalyst,
-  vibrational: FilterSubMenuVibrational,
-  mechanical: FilterSubMenuMechanical,
-  molecular_dynamics: FilterSubMenuMolecularDynamics,
-  geometry_optimization: FilterSubMenuGeometryOptimization,
-  eln: FilterSubMenuELN,
-  custom_quantities: FilterSubMenuCustomQuantities,
-  author: FilterSubMenuAuthor,
-  metadata: FilterSubMenuMetadata,
-  optimade: FilterSubMenuOptimade
-}
-
-const useFilterMainMenuStyles = makeStyles(theme => ({
-  combine: {
-  }
-}))
-
-/**
- * Swipable menu that shows the available filters on the left side of the
- * screen.
- */
-const FilterMainMenu = React.memo(({
-  open,
-  onOpenChange,
-  collapsed,
-  onCollapsedChange
-}) => {
-  const [value, setValue] = React.useState()
-  const {filterMenus} = useSearchContext()
-  const [loaded, setLoaded] = useState(false)
-  const styles = useFilterMainMenuStyles()
-
-  // Rendering the submenus is delayed on the event queue: this makes loading
-  // the search page more responsive by first loading everything else.
-  useEffect(() => {
-    delay(() => { setLoaded(true) })
-  }, [])
-
-  // The shown menu items
-  const menuItems = useMemo(() => {
-    return filterMenus?.options
-     ? Object.values(filterMenus.options).map(option => {
-        return <FilterMenuItem
-          key={option.key}
-          id={option.key}
-          label={option.label}
-          level={option.level}
-          disableButton={!has(menuMap, option.key)}
-          actions={option?.actions?.options && Object.values(option.actions.options)
-            .map((action) => {
-              const content = action.type === 'checkbox'
-                ? <InputCheckbox
-                  key={action.key}
-                  quantity={action.quantity}
-                  description={action.tooltip}
-                  label={action.label}
-                  className={styles.combine}
-                ></InputCheckbox>
-                : null
-              return content
-          })}
-        />
-      })
-    : <Alert severity="warning">
-      No search menus defined within this search context. Ensure that all GUI artifacts are created.
-    </Alert>
-  }, [filterMenus, styles])
-
-  // The shown submenus
-  const subMenus = useMemo(() => {
-    return filterMenus?.options
-      ? Object.values(filterMenus.options)
-        .filter(option => menuMap[option.key])
-        .map(option => {
-          const Comp = menuMap[option.key]
-          return <Comp
-            key={option.key}
-            id={option.key}
-            label={option.label}
-            size={option.size}
-          />
-        })
-      : null
-  }, [filterMenus])
-
-  return <FilterMenu
-    selected={value}
-    onSelectedChange={setValue}
-    open={open}
-    onOpenChange={onOpenChange}
-    collapsed={collapsed}
-    onCollapsedChange={onCollapsedChange}
-  >
-    <FilterMenuItems>
-      {menuItems}
-    </FilterMenuItems>
-    <FilterSubMenus>
-      {loaded && subMenus}
-    </FilterSubMenus>
-  </FilterMenu>
-})
-FilterMainMenu.propTypes = {
-  open: PropTypes.bool,
-  onOpenChange: PropTypes.func,
-  collapsed: PropTypes.bool,
-  onCollapsedChange: PropTypes.func
-}
-
-export default FilterMainMenu
diff --git a/gui/src/components/search/menus/FilterMenu.js b/gui/src/components/search/menus/FilterMenu.js
deleted file mode 100644
index a53dd697f1..0000000000
--- a/gui/src/components/search/menus/FilterMenu.js
+++ /dev/null
@@ -1,646 +0,0 @@
-/*
- * Copyright The NOMAD Authors.
- *
- * This file is part of NOMAD. See https://nomad-lab.eu for further info.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React, { useState, useCallback, useContext, useEffect } from 'react'
-import PropTypes from 'prop-types'
-import clsx from 'clsx'
-import { makeStyles, useTheme } from '@material-ui/core/styles'
-import {
-  List,
-  ListItem,
-  ListItemText,
-  ListItemIcon,
-  Divider,
-  Paper,
-  Menu,
-  Typography
-} from '@material-ui/core'
-import ArrowForwardIcon from '@material-ui/icons/ArrowForward'
-import ArrowBackIcon from '@material-ui/icons/ArrowBack'
-import NavigateNextIcon from '@material-ui/icons/NavigateNext'
-import MoreVert from '@material-ui/icons/MoreVert'
-import Scrollable from '../../visualization/Scrollable'
-import FilterSettings from './FilterSettings'
-import { Actions, ActionHeader, Action } from '../../Actions'
-import { useSearchContext } from '../SearchContext'
-import { pluralize } from '../../../utils'
-import { isNil } from 'lodash'
-
-// The menu animations use a transition on the 'transform' property. Notice that
-// animating 'transform' instead of e.g. the 'left' property is much more
-// performant. We also hint the browser that the transform property will be
-// animated using the 'will-change' property: this will pre-optimize the element
-// for animation when possible (the recommendation is to remove/add it when
-// needed, but in this case we keep it on constantly).
-//
-// The menu widths are hardcoded. We need the widths to perform the close
-// animation. Another option would be to use useLayoutEffect to determine the
-// sizes of the components dynamically, but this seems to be quite a bit less
-// responsive compared to hardcoding the values.
-
-export const filterMenuContext = React.createContext()
-const paddingHorizontal = 1.5
-export const collapsedMenuWidth = 3.3
-
-// Topmost header for filter menus. Contains menu actions and an overline text
-const useFilterMenuTopHeaderStyles = makeStyles(theme => {
-  return {
-    root: {
-      paddingTop: theme.spacing(1.2),
-      paddingRight: theme.spacing(paddingHorizontal),
-      paddingLeft: theme.spacing(paddingHorizontal)
-    },
-    title: {
-      display: 'flex',
-      alignItems: 'center',
-      fontSize: '0.75rem',
-      marginTop: -3,
-      marginBottom: -3
-    }
-  }
-})
-export const FilterMenuTopHeader = React.memo(({
-  title,
-  actions,
-  className
-}) => {
-  const styles = useFilterMenuTopHeaderStyles()
-  return <div className={clsx(className, styles.root)}>
-    <Actions>
-      <ActionHeader>
-        <Typography className={styles.title} variant="overline">{title}</Typography>
-      </ActionHeader>
-      {actions}
-    </Actions>
-  </div>
-})
-FilterMenuTopHeader.propTypes = {
-  overlineTitle: PropTypes.string,
-  title: PropTypes.string,
-  topAction: PropTypes.node,
-  actions: PropTypes.node,
-  className: PropTypes.string
-}
-
-// Header for filter menus. Contains panel actions and an overline text.
-const useFilterMenuHeaderStyles = makeStyles(theme => {
-  return {
-    root: {
-      height: theme.spacing(3),
-      paddingBottom: theme.spacing(1.1),
-      paddingTop: theme.spacing(0.3),
-      paddingLeft: theme.spacing(paddingHorizontal),
-      paddingRight: theme.spacing(paddingHorizontal),
-      display: 'flex',
-      flexDirection: 'column',
-      justifyContent: 'center'
-    },
-    title: {
-      display: 'flex',
-      alignItems: 'center',
-      fontSize: '0.90rem'
-    }
-  }
-})
-export const FilterMenuHeader = React.memo(({
-  title,
-  actions,
-  className,
-  'data-testid': testID
-}) => {
-  const styles = useFilterMenuHeaderStyles()
-  return <div className={clsx(className, styles.root)} data-testid={testID}>
-    <Actions>
-      <ActionHeader>
-        <Typography className={styles.title} variant="button">{title}</Typography>
-      </ActionHeader>
-      {actions}
-    </Actions>
-  </div>
-})
-
-FilterMenuHeader.propTypes = {
-  overlineTitle: PropTypes.string,
-  title: PropTypes.string,
-  topAction: PropTypes.node,
-  actions: PropTypes.node,
-  className: PropTypes.string,
-  'data-testid': PropTypes.string
-}
-
-const useFilterMenuStyles = makeStyles(theme => {
-  const width = 22
-  return {
-    root: {
-      boxSizing: 'border-box',
-      display: 'flex',
-      position: 'relative',
-      flexDirection: 'column',
-      width: `${width}rem`,
-      height: '100%',
-      '-webkit-transform': 'none',
-      transform: 'none',
-      transition: 'transform 250ms',
-      willChange: 'transform'
-    },
-    collapsed: {
-      '-webkit-transform': `translateX(-${width - collapsedMenuWidth}rem)`,
-      transform: `translateX(-${width - collapsedMenuWidth}rem)`
-    }
-  }
-})
-
-export const FilterMenu = React.memo(({
-  selected,
-  onSelectedChange,
-  open,
-  onOpenChange,
-  collapsed,
-  onCollapsedChange,
-  className,
-  children
-}) => {
-  const styles = useFilterMenuStyles()
-  const [size, setSize] = useState('m')
-
-  const handleChange = useCallback((newValue) => {
-    if (newValue !== selected) {
-      onOpenChange(true)
-    } else {
-      onOpenChange(old => !old)
-    }
-    onSelectedChange && onSelectedChange(newValue)
-  }, [selected, onSelectedChange, onOpenChange])
-
-  return <div className={clsx(className, styles.root, collapsed && styles.collapsed)}>
-    <filterMenuContext.Provider value={{
-      selected: selected,
-      onChange: handleChange,
-      open: open,
-      onOpenChange: onOpenChange,
-      size: size,
-      onSizeChange: setSize,
-      collapsed: collapsed,
-      onCollapsedChange: onCollapsedChange
-    }}>
-      {children}
-    </filterMenuContext.Provider>
-  </div>
-})
-FilterMenu.propTypes = {
-  selected: PropTypes.string,
-  onSelectedChange: PropTypes.func,
-  open: PropTypes.bool,
-  onOpenChange: PropTypes.func,
-  collapsed: PropTypes.bool,
-  onCollapsedChange: PropTypes.func,
-  className: PropTypes.string,
-  children: PropTypes.node
-}
-
-const useFilterMenuItemsStyles = makeStyles(theme => {
-  return {
-    root: {
-      boxSizing: 'border-box',
-      display: 'flex',
-      flexDirection: 'column',
-      width: '100%',
-      height: '100%',
-      backgroundColor: theme.palette.background.paper,
-      zIndex: 3
-    },
-    headerTextVertical: {
-      display: 'flex',
-      alignItems: 'center',
-      position: 'absolute',
-      right: '0.07rem',
-      top: '2.5rem',
-      height: `${collapsedMenuWidth}rem`,
-      transform: 'rotate(90deg)'
-    },
-    menu: {
-      position: 'absolute',
-      right: 0,
-      top: 0,
-      bottom: 0,
-      left: 0,
-      boxSizing: 'border-box'
-    },
-    menuBorder: {
-      boxShadow: `1px 0px 0px 0px ${theme.palette.action.selected}`
-    },
-    padding: {
-      paddingBottom: `${theme.spacing(1.5)}px`
-    },
-    button: {
-      marginRight: 0,
-      '-webkit-transform': 'none',
-      transform: 'none',
-      transition: 'transform 250ms',
-      willChange: 'transform'
-    },
-    hidden: {
-      display: 'none'
-    },
-    overflow: {
-      overflow: 'visible'
-    },
-    list: {
-      paddingTop: 0
-    },
-    container: {
-      display: 'flex',
-      flexDirection: 'column',
-      height: '100%'
-    },
-    content: {
-      flex: 1,
-      minHeight: 0
-    },
-    collapsedActions: {
-      paddingTop: theme.spacing(0.7),
-      paddingLeft: theme.spacing(paddingHorizontal),
-      paddingRight: theme.spacing(paddingHorizontal)
-    }
-  }
-})
-export const FilterMenuItems = React.memo(({
-  className,
-  children
-}) => {
-  // const { useResetFilters, useRefresh, useApiData } = useSearchContext()
-  const styles = useFilterMenuItemsStyles()
-  const { open, onOpenChange, collapsed, onCollapsedChange } = useContext(filterMenuContext)
-  const [anchorEl, setAnchorEl] = React.useState(null)
-  const isSettingsOpen = Boolean(anchorEl)
-
-  // Callbacks
-  const openMenu = useCallback((event) => {
-    setAnchorEl(event.currentTarget)
-  }, [])
-  const closeMenu = useCallback(() => {
-    setAnchorEl(null)
-  }, [])
-
-  // Unfortunately the ClickAwayListener does not play nicely together with
-  // Menus/Select/Popper. When using Portals, the clicks are registered wrong.
-  // When Portals are disabled (disablePortal), their positioning goes haywire.
-  // The clicks outside are thus detected by individual event listeners that
-  // toggle the menu state.
-  return <div className={clsx(className, styles.root)}>
-    <div className={clsx(styles.menu, open && styles.menuBorder, collapsed && styles.hidden)}>
-      <div className={styles.container}>
-        <FilterMenuTopHeader/>
-        <FilterMenuHeader
-          title="Filters"
-          actions={<>
-            <Action
-              tooltip={'Hide filter menu'}
-              onClick={() => {
-                onCollapsedChange(old => !old)
-                onOpenChange(false)
-              }}
-              // className={styles.button}
-            >
-              <ArrowBackIcon fontSize="small"/>
-            </Action>
-            <Action
-              tooltip="Options"
-              onClick={openMenu}
-            >
-              <MoreVert fontSize="small"/>
-            </Action>
-            <Menu
-              anchorEl={anchorEl}
-              open={isSettingsOpen}
-              onClose={closeMenu}
-              getContentAnchorEl={null}
-              anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
-              transformOrigin={{ vertical: 'top', horizontal: 'right' }}
-              keepMounted
-            >
-              <div>
-                <FilterSettings/>
-              </div>
-            </Menu>
-          </>}
-        />
-        <div className={styles.content}>
-          <Scrollable>
-            <div className={styles.padding}>
-              <Divider/>
-              <List dense className={styles.list}>
-                {children}
-              </List>
-            </div>
-          </Scrollable>
-        </div>
-      </div>
-    </div>
-    <div className={clsx(!collapsed && styles.hidden)}>
-      <Actions className={styles.collapsedActions}>
-        {collapsed && <Action
-          tooltip={'Show filter menu'}
-          onClick={() => {
-            onCollapsedChange(false)
-          }}
-          className={styles.button}
-        >
-          <ArrowForwardIcon fontSize="small"/>
-        </Action>}
-      </Actions>
-      <Typography
-        className={clsx(styles.headerText, styles.headerTextVertical)}
-        variant="button"
-      >Filters
-      </Typography>
-    </div>
-  </div>
-})
-FilterMenuItems.propTypes = {
-  className: PropTypes.string,
-  children: PropTypes.node
-}
-
-const levelIndent = 1.8
-const leftGutter = 3.0
-const rightGutter = 2.35
-const itemHeight = 2.6
-const useFilterMenuItemStyles = makeStyles(theme => {
-  return {
-    root: {
-      minHeight: `${itemHeight}rem`
-    },
-    label: {
-      textTransform: 'capitalize'
-    },
-    listIcon: {
-      fontsize: '1rem',
-      minWidth: '1.5rem'
-    },
-    arrow: {
-      marginLeft: theme.spacing(1),
-      fontSize: '1.5rem'
-    },
-    gutters: {
-      paddingLeft: theme.spacing(leftGutter),
-      paddingRight: theme.spacing(rightGutter)
-    },
-    listItem: {
-      position: 'relative',
-      height: `${itemHeight}rem`
-    },
-    actions: {
-      display: 'flex',
-      flexDirection: 'column',
-      paddingLeft: theme.spacing(leftGutter),
-      paddingRight: theme.spacing(rightGutter)
-    },
-    divider: {
-      width: '100%',
-      backgroundColor: theme.palette.grey[300]
-    }
-  }
-})
-export const FilterMenuItem = React.memo(({
-  id,
-  label,
-  onClick,
-  actions,
-  disableButton,
-  level
-}) => {
-  const styles = useFilterMenuItemStyles()
-  const theme = useTheme()
-  const { selected, open, onChange } = useContext(filterMenuContext)
-  const handleClick = disableButton ? undefined : (onClick || onChange)
-  const opened = open && id === selected
-
-  return <div className={styles.root}>
-    {(label || handleClick) &&
-    <ListItem
-      button={!!handleClick}
-      className={styles.listItem}
-      classes={{gutters: styles.gutters}}
-      onClick={handleClick && (() => handleClick(id))}
-    >
-      {label && <ListItemText
-        style={{marginLeft: theme.spacing(level * levelIndent)}}
-        primaryTypographyProps={{
-          color: opened ? 'primary' : 'initial',
-          className: styles.label
-        }}
-        primary={label}
-        data-testid={`menu-item-label-${id}`}
-      />}
-      {handleClick && <ListItemIcon className={styles.listIcon}>
-        <NavigateNextIcon color={opened ? 'primary' : 'action'} className={styles.arrow}/>
-      </ListItemIcon>}
-    </ListItem>}
-    {actions && <div
-      className={styles.actions}
-      style={{marginLeft: theme.spacing(level * levelIndent)}}
-    >
-      {actions}
-    </div>}
-    <Divider className={styles.divider}/>
-  </div>
-})
-
-FilterMenuItem.propTypes = {
-  id: PropTypes.string,
-  label: PropTypes.string,
-  onClick: PropTypes.func,
-  actions: PropTypes.node,
-  disableButton: PropTypes.bool,
-  level: PropTypes.number
-}
-FilterMenuItem.defaultProps = {
-  level: 0
-}
-
-const useFilterSubMenusStyles = makeStyles(theme => {
-  const widthS = 25
-  const widthM = 32
-  const widthL = 40
-  const widthXL = 48
-  return {
-    root: {
-      zIndex: 2,
-      display: 'flex',
-      flexDirection: 'column',
-      position: 'absolute',
-      right: 0,
-      top: 0,
-      bottom: 0,
-      width: `${widthXL}rem`,
-      backgroundColor: theme.palette.background.paper,
-      '-webkit-transform': 'none',
-      transform: 'none',
-      transition: 'transform 250ms',
-      flexGrow: 1,
-      boxSizing: 'border-box',
-      willChange: 'transform'
-    },
-    collapsed: {
-      display: 'none'
-    },
-    containerS: {
-      '-webkit-transform': `translateX(${widthS}rem)`,
-      transform: `translateX(${widthS}rem)`
-    },
-    containerM: {
-      '-webkit-transform': `translateX(${widthM}rem)`,
-      transform: `translateX(${widthM}rem)`
-    },
-    containerL: {
-      '-webkit-transform': `translateX(${widthL}rem)`,
-      transform: `translateX(${widthL}rem)`
-    },
-    containerXL: {
-      '-webkit-transform': `translateX(${widthXL}rem)`,
-      transform: `translateX(${widthXL}rem)`
-    },
-    menu: {
-      position: 'absolute',
-      right: 0,
-      top: 0,
-      bottom: 0,
-      boxSizing: 'border-box',
-      display: 'flex',
-      flexDirection: 'column'
-    },
-    content: {
-      flex: 1,
-      minHeight: 0
-    },
-    menuS: {
-      width: `${widthS}rem`
-    },
-    menuM: {
-      width: `${widthM}rem`
-    },
-    menuL: {
-      width: `${widthL}rem`
-    },
-    menuXL: {
-      width: `${widthXL}rem`
-    },
-    button: {
-      marginRight: 0
-    }
-  }
-})
-
-export const FilterSubMenus = React.memo(({
-  children
-}) => {
-  const { useResults } = useSearchContext()
-  const nResults = useResults()?.pagination?.total
-  const styles = useFilterSubMenusStyles()
-  const { open, onOpenChange, size, collapsed } = useContext(filterMenuContext)
-  const [menuStyle, containerStyle] = {
-    s: [styles.menuS, styles.containerS],
-    m: [styles.menuM, styles.containerM],
-    l: [styles.menuL, styles.containerL],
-    xl: [styles.menuXL, styles.containerXL]
-  }[size]
-
-  return <Paper
-    elevation={4}
-    className={clsx(styles.root, open && containerStyle)}
-  >
-    <div className={clsx(styles.menu, menuStyle, collapsed && styles.collapsed)}>
-      <FilterMenuTopHeader
-        title={isNil(nResults) ? 'loading...' : pluralize('result', nResults, true)}
-        actions={<Action
-          tooltip="Close submenu"
-          onClick={() => { onOpenChange(false) }}
-          className={styles.button}
-        >
-          <ArrowBackIcon fontSize="small"/>
-        </Action>}
-      />
-      <div className={styles.content}>
-        {children}
-      </div>
-    </div>
-  </Paper>
-})
-FilterSubMenus.propTypes = {
-  sizes: PropTypes.object,
-  children: PropTypes.node
-}
-
-const useFilterSubMenuStyles = makeStyles(theme => ({
-  root: {
-    width: '100%',
-    height: '100%',
-    display: 'flex',
-    flexDirection: 'column'
-  },
-  hidden: {
-    display: 'none'
-  },
-  padding: {
-    paddingBottom: theme.spacing(1.5),
-    paddingLeft: theme.spacing(paddingHorizontal),
-    paddingRight: theme.spacing(paddingHorizontal)
-  },
-  content: {
-    flex: 1,
-    minHeight: 0
-  }
-}))
-
-export const FilterSubMenu = React.memo(({
-  id,
-  label,
-  size,
-  actions,
-  children
-}) => {
-  const styles = useFilterSubMenuStyles()
-  const { selected, onSizeChange } = useContext(filterMenuContext)
-  const visible = id === selected
-  useEffect(() => {
-    if (visible) {
-      onSizeChange(size)
-    }
-  }, [size, visible, onSizeChange])
-
-  return <div className={clsx(styles.root, !visible && styles.hidden)}>
-    <FilterMenuHeader title={label} actions={actions} data-testid={`filter-menu-header-${id}`}/>
-    <div className={styles.content}>
-      <Scrollable>
-        {children}
-      </Scrollable>
-    </div>
-  </div>
-})
-FilterSubMenu.propTypes = {
-  id: PropTypes.string,
-  label: PropTypes.string,
-  size: PropTypes.oneOf(['s', 'm', 'l', 'xl']),
-  actions: PropTypes.node,
-  children: PropTypes.node
-}
-FilterSubMenu.defaultProps = {
-  size: 's'
-}
-
-export default FilterSubMenu
diff --git a/gui/src/components/search/menus/FilterSettings.js b/gui/src/components/search/menus/FilterSettings.js
deleted file mode 100644
index e3a14660a7..0000000000
--- a/gui/src/components/search/menus/FilterSettings.js
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright The NOMAD Authors.
- *
- * This file is part of NOMAD. See https://nomad-lab.eu for further info.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React, { useCallback } from 'react'
-import { makeStyles } from '@material-ui/core/styles'
-import {
-  Checkbox,
-  MenuItem,
-  FormControlLabel
-} from '@material-ui/core'
-import PropTypes from 'prop-types'
-import clsx from 'clsx'
-import { useSearchContext } from '../SearchContext'
-
-/**
- * Menu showing the Filter settings.
- */
-const useStyles = makeStyles((theme) => {
-  return {
-    root: {
-    },
-    menuItem: {
-      width: '10rem'
-    },
-    systems: {
-      margin: theme.spacing(2),
-      marginTop: theme.spacing(1)
-    }
-  }
-})
-const FilterSettings = React.memo(({
-  className,
-  classes,
-  'data-testid': testID
-}) => {
-  const styles = useStyles(classes)
-  const {
-    useIsStatisticsEnabled,
-    useSetIsStatisticsEnabled
-  } = useSearchContext()
-  const [isStatisticsEnabled, setIsStatisticsEnabled] = [useIsStatisticsEnabled(), useSetIsStatisticsEnabled()]
-
-  const handleStatsChange = useCallback((event, value) => {
-    setIsStatisticsEnabled(value)
-  }, [setIsStatisticsEnabled])
-
-  return <div className={clsx(styles.root, className)} data-testid={testID}>
-    <MenuItem>
-      <FormControlLabel
-        control={<Checkbox
-          checked={isStatisticsEnabled}
-          onChange={handleStatsChange}
-        />}
-        label="Show advanced statistics"
-      />
-    </MenuItem>
-  </div>
-})
-
-FilterSettings.propTypes = {
-  className: PropTypes.string,
-  classes: PropTypes.object,
-  'data-testid': PropTypes.string
-}
-
-export default FilterSettings
diff --git a/gui/src/components/search/menus/FilterSubMenuAuthor.js b/gui/src/components/search/menus/FilterSubMenuAuthor.js
deleted file mode 100644
index b8e1744691..0000000000
--- a/gui/src/components/search/menus/FilterSubMenuAuthor.js
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright The NOMAD Authors.
- *
- * This file is part of NOMAD. See https://nomad-lab.eu for further info.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React, { useContext } from 'react'
-import PropTypes from 'prop-types'
-import { FilterSubMenu, filterMenuContext } from './FilterMenu'
-import { InputGrid, InputGridItem } from '../input/InputGrid'
-import InputField from '../input/InputField'
-import InputRange from '../input/InputRange'
-
-const FilterSubMenuAuthor = React.memo(({
-  id,
-  ...rest
-}) => {
-  const {selected, open} = useContext(filterMenuContext)
-  const visible = open && id === selected
-
-  return <FilterSubMenu id={id} {...rest}>
-    <InputGrid>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="authors.name"
-          visible={visible}
-          disableOptions
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputRange
-          quantity="upload_create_time"
-          visible={visible}
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="external_db"
-          visible={visible}
-          disableSearch
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="datasets.dataset_name"
-          visible={visible}
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="datasets.doi"
-          visible={visible}
-          disableStatistics
-          disableOptions
-        />
-      </InputGridItem>
-    </InputGrid>
-  </FilterSubMenu>
-})
-FilterSubMenuAuthor.propTypes = {
-  id: PropTypes.string
-}
-
-export default FilterSubMenuAuthor
diff --git a/gui/src/components/search/menus/FilterSubMenuBSE.js b/gui/src/components/search/menus/FilterSubMenuBSE.js
deleted file mode 100644
index 64062c41fe..0000000000
--- a/gui/src/components/search/menus/FilterSubMenuBSE.js
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright The NOMAD Authors.
- *
- * This file is part of NOMAD. See https://nomad-lab.eu for further info.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React, { useContext } from 'react'
-import PropTypes from 'prop-types'
-import { FilterSubMenu, filterMenuContext } from './FilterMenu'
-import { InputGrid, InputGridItem } from '../input/InputGrid'
-import InputField from '../input/InputField'
-import { InputCheckboxValue } from '../input/InputCheckbox'
-
-const FilterSubMenuBSE = React.memo(({
-  id,
-  ...rest
-}) => {
-  const {selected, open} = useContext(filterMenuContext)
-  const visible = open && id === selected
-
-  return <FilterSubMenu
-    id={id}
-    actions={<InputCheckboxValue
-      quantity="results.method.method_name"
-      value="BSE"
-      description="Search BSE entries"
-    />}
-    {...rest}>
-    <InputGrid>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.method.simulation.bse.type"
-          visible={visible}
-          xs={12}
-          disableSearch
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.method.simulation.bse.solver"
-          visible={visible}
-          xs={12}
-          disableSearch
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.method.simulation.bse.starting_point_type"
-          visible={visible}
-          xs={12}
-          disableSearch
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.method.simulation.bse.basis_set_type"
-          visible={visible}
-          xs={12}
-          disableSearch
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.method.simulation.bse.gw_type"
-          visible={visible}
-          xs={12}
-          disableSearch
-        />
-      </InputGridItem>
-    </InputGrid>
-  </FilterSubMenu>
-})
-FilterSubMenuBSE.propTypes = {
-  id: PropTypes.string
-}
-
-export default FilterSubMenuBSE
diff --git a/gui/src/components/search/menus/FilterSubMenuCatalystProperties.js b/gui/src/components/search/menus/FilterSubMenuCatalystProperties.js
deleted file mode 100755
index 01ba2911f2..0000000000
--- a/gui/src/components/search/menus/FilterSubMenuCatalystProperties.js
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright The NOMAD Authors.
- *
- * This file is part of NOMAD. See https://nomad-lab.eu for further info.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React, { useContext } from 'react'
-import PropTypes from 'prop-types'
-import { FilterSubMenu, filterMenuContext } from './FilterMenu'
-import { InputGrid, InputGridItem } from '../input/InputGrid'
-import InputSection from '../input/InputSection'
-import InputRange from '../input/InputRange'
-import InputField from '../input/InputField'
-
-const FilterSubMenuCatalyst = React.memo(({
-  id,
-  ...rest
-}) => {
-  const {selected, open} = useContext(filterMenuContext)
-  const visible = open && id === selected
-
-  return <FilterSubMenu id={id} {...rest}>
-    <InputGrid>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.properties.catalytic.reaction.name"
-          visible={visible}
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputSection
-          section="results.properties.catalytic.reaction.reactants"
-          visible={visible}
-        >
-          <InputField
-          quantity="results.properties.catalytic.reaction.reactants.name"
-          visible={visible}
-          />
-          <InputRange
-          quantity="results.properties.catalytic.reaction.reactants.conversion"
-          visible={visible}
-          />
-          <InputRange
-          quantity="results.properties.catalytic.reaction.reactants.gas_concentration_in"
-          visible={visible}
-          />
-          <InputRange
-          quantity="results.properties.catalytic.reaction.reactants.gas_concentration_out"
-          visible={visible}
-          />
-        </InputSection>
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputSection
-          section="results.properties.catalytic.reaction.products"
-          visible={visible}
-        >
-          <InputField
-          quantity="results.properties.catalytic.reaction.products.name"
-          visible={visible}
-          />
-          <InputRange
-          quantity="results.properties.catalytic.reaction.products.selectivity"
-          visible={visible}
-          />
-          <InputRange
-          quantity="results.properties.catalytic.reaction.products.gas_concentration_out"
-          visible={visible}
-          />
-        </InputSection>
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputRange
-          quantity="results.properties.catalytic.reaction.reaction_conditions.temperature"
-          visible={visible}
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputSection
-          section="results.properties.catalytic.catalyst"
-          disableHeader
-          visible={visible}
-        >
-          <InputField
-            quantity="results.properties.catalytic.catalyst.catalyst_type"
-            visible={visible}
-          />
-          <InputField
-            quantity="results.properties.catalytic.catalyst.preparation_method"
-            visible={visible}
-          />
-          <InputField
-            quantity="results.properties.catalytic.catalyst.catalyst_name"
-            visible={visible}
-          />
-          <InputField
-            quantity="results.properties.catalytic.catalyst.characterization_methods"
-            visible={visible}
-          />
-          <InputRange
-            quantity="results.properties.catalytic.catalyst.surface_area"
-            visible={visible}
-          />
-        </InputSection>
-      </InputGridItem>
-    </InputGrid>
-  </FilterSubMenu>
-})
-FilterSubMenuCatalyst.propTypes = {
-  id: PropTypes.string
-}
-
-export default FilterSubMenuCatalyst
diff --git a/gui/src/components/search/menus/FilterSubMenuDFT.js b/gui/src/components/search/menus/FilterSubMenuDFT.js
deleted file mode 100644
index 3b7626082b..0000000000
--- a/gui/src/components/search/menus/FilterSubMenuDFT.js
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright The NOMAD Authors.
- *
- * This file is part of NOMAD. See https://nomad-lab.eu for further info.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React, { useContext } from 'react'
-import PropTypes from 'prop-types'
-import { FilterSubMenu, filterMenuContext } from './FilterMenu'
-import { InputGrid, InputGridItem } from '../input/InputGrid'
-import InputField from '../input/InputField'
-import InputRange from '../input/InputRange'
-import { InputCheckboxValue } from '../input/InputCheckbox'
-
-const FilterSubMenuDFT = React.memo(({
-  id,
-  ...rest
-}) => {
-  const {selected, open} = useContext(filterMenuContext)
-  const visible = open && id === selected
-
-  return <FilterSubMenu
-    id={id}
-    actions={<InputCheckboxValue
-      quantity="results.method.method_name"
-      value="DFT"
-      description="Search DFT entries"
-    />}
-    {...rest}
-  >
-    <InputGrid>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.method.simulation.dft.xc_functional_type"
-          visible={visible}
-          xs={12}
-          disableSearch
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.method.simulation.dft.xc_functional_names"
-          visible={visible}
-          xs={12}
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputRange
-          quantity="results.method.simulation.dft.exact_exchange_mixing_factor"
-          visible={visible}
-          xs={12}
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputRange
-          quantity="results.method.simulation.dft.hubbard_kanamori_model.u_effective"
-          visible={visible}
-          xs={12}
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.method.simulation.dft.core_electron_treatment"
-          visible={visible}
-          disableSearch
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.method.simulation.dft.relativity_method"
-          visible={visible}
-          disableSearch
-        />
-      </InputGridItem>
-    </InputGrid>
-  </FilterSubMenu>
-})
-FilterSubMenuDFT.propTypes = {
-  id: PropTypes.string
-}
-
-export default FilterSubMenuDFT
diff --git a/gui/src/components/search/menus/FilterSubMenuDMFT.js b/gui/src/components/search/menus/FilterSubMenuDMFT.js
deleted file mode 100644
index ca5e0bd46e..0000000000
--- a/gui/src/components/search/menus/FilterSubMenuDMFT.js
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright The NOMAD Authors.
- *
- * This file is part of NOMAD. See https://nomad-lab.eu for further info.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React, { useContext } from 'react'
-import PropTypes from 'prop-types'
-import { FilterSubMenu, filterMenuContext } from './FilterMenu'
-import { InputGrid, InputGridItem } from '../input/InputGrid'
-import InputField from '../input/InputField'
-import InputRange from '../input/InputRange'
-import { InputCheckboxValue } from '../input/InputCheckbox'
-
-const FilterSubMenuDMFT = React.memo(({
-  id,
-  ...rest
-}) => {
-  const {selected, open} = useContext(filterMenuContext)
-  const visible = open && id === selected
-
-  return <FilterSubMenu
-    id={id}
-    actions={<InputCheckboxValue
-      quantity="results.method.method_name"
-      value="DMFT"
-      description="Search DMFT entries"
-    />}
-    {...rest}>
-    <InputGrid>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.method.simulation.dmft.impurity_solver_type"
-          visible={visible}
-          xs={12}
-          disableSearch
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputRange
-          quantity="results.method.simulation.dmft.inverse_temperature"
-          visible={visible}
-          xs={12}
-          disableSearch
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.method.simulation.dmft.magnetic_state"
-          visible={visible}
-          xs={12}
-          disableSearch
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputRange
-          quantity="results.method.simulation.dmft.u"
-          visible={visible}
-          xs={12}
-          disableSearch
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputRange
-          quantity="results.method.simulation.dmft.jh"
-          visible={visible}
-          xs={12}
-          disableSearch
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.method.simulation.dmft.analytical_continuation"
-          visible={visible}
-          xs={12}
-          disableSearch
-        />
-      </InputGridItem>
-    </InputGrid>
-  </FilterSubMenu>
-})
-FilterSubMenuDMFT.propTypes = {
-  id: PropTypes.string
-}
-
-export default FilterSubMenuDMFT
diff --git a/gui/src/components/search/menus/FilterSubMenuEELS.js b/gui/src/components/search/menus/FilterSubMenuEELS.js
deleted file mode 100644
index 6339df01fa..0000000000
--- a/gui/src/components/search/menus/FilterSubMenuEELS.js
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright The NOMAD Authors.
- *
- * This file is part of NOMAD. See https://nomad-lab.eu for further info.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React, { useContext } from 'react'
-import PropTypes from 'prop-types'
-import { FilterSubMenu, filterMenuContext } from './FilterMenu'
-import { InputGrid, InputGridItem } from '../input/InputGrid'
-import InputField from '../input/InputField'
-import InputRange from '../input/InputRange'
-import InputSection from '../input/InputSection'
-import { InputCheckboxValue } from '../input/InputCheckbox'
-
-const FilterSubMenuEELS = React.memo(({
-  id,
-  ...rest
-}) => {
-  const {selected, open} = useContext(filterMenuContext)
-  const visible = open && id === selected
-
-  return <FilterSubMenu
-    id={id}
-    actions={<InputCheckboxValue
-      quantity="results.method.method_name"
-      value="EELS"
-      description="Search EELS entries"
-    />}
-    {...rest}>
-    <InputGrid>
-      <InputGridItem xs={12}>
-        <InputSection
-          section="results.properties.spectroscopic.spectra.provenance.eels"
-          disableHeader
-          visible={visible}
-        >
-          <InputField
-            quantity="results.properties.spectroscopic.spectra.provenance.eels.detector_type"
-            visible={visible}
-            xs={12}
-          />
-          <InputRange
-            quantity="results.properties.spectroscopic.spectra.provenance.eels.resolution"
-            visible={visible}
-          />
-          <InputRange
-            quantity="results.properties.spectroscopic.spectra.provenance.eels.min_energy"
-            visible={visible}
-          />
-          <InputRange
-            quantity="results.properties.spectroscopic.spectra.provenance.eels.max_energy"
-            visible={visible}
-          />
-        </InputSection>
-      </InputGridItem>
-    </InputGrid>
-  </FilterSubMenu>
-})
-FilterSubMenuEELS.propTypes = {
-  id: PropTypes.string
-}
-
-export default FilterSubMenuEELS
diff --git a/gui/src/components/search/menus/FilterSubMenuELN.js b/gui/src/components/search/menus/FilterSubMenuELN.js
deleted file mode 100644
index c5566bb136..0000000000
--- a/gui/src/components/search/menus/FilterSubMenuELN.js
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright The NOMAD Authors.
- *
- * This file is part of NOMAD. See https://nomad-lab.eu for further info.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React, { useContext } from 'react'
-import PropTypes from 'prop-types'
-import { FilterSubMenu, filterMenuContext } from './FilterMenu'
-import { InputGrid, InputGridItem } from '../input/InputGrid'
-import InputField from '../input/InputField'
-import { InputCheckboxValue } from '../input/InputCheckbox'
-
-const FilterSubMenuELN = React.memo(({
-  id,
-  ...rest
-}) => {
-  const {selected, open} = useContext(filterMenuContext)
-  const visible = open && id === selected
-
-  return <FilterSubMenu
-    id={id}
-    actions={<InputCheckboxValue
-      quantity="quantities"
-      value="data"
-      description="Search ELN entries"
-    />}
-    {...rest}
-  >
-    <InputGrid>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.eln.sections"
-          visible={visible}
-          xs={12}
-          disableSearch
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.eln.tags"
-          visible={visible}
-          xs={12}
-          disableSearch
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.eln.methods"
-          visible={visible}
-          xs={12}
-          disableSearch
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.eln.instruments"
-          visible={visible}
-          xs={12}
-          disableSearch
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.eln.names"
-          visible={visible}
-          disableStatistics
-          disableOptions
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.eln.descriptions"
-          visible={visible}
-          disableStatistics
-          disableOptions
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.eln.lab_ids"
-          visible={visible}
-          disableStatistics
-          disableOptions
-        />
-      </InputGridItem>
-    </InputGrid>
-  </FilterSubMenu>
-})
-FilterSubMenuELN.propTypes = {
-  id: PropTypes.string
-}
-
-export default FilterSubMenuELN
diff --git a/gui/src/components/search/menus/FilterSubMenuElectronic.js b/gui/src/components/search/menus/FilterSubMenuElectronic.js
deleted file mode 100644
index 27beef3cab..0000000000
--- a/gui/src/components/search/menus/FilterSubMenuElectronic.js
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright The NOMAD Authors.
- *
- * This file is part of NOMAD. See https://nomad-lab.eu for further info.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React, { useContext } from 'react'
-import PropTypes from 'prop-types'
-import { FilterSubMenu, filterMenuContext } from './FilterMenu'
-import { InputGrid, InputGridItem } from '../input/InputGrid'
-import InputSection from '../input/InputSection'
-import InputRange from '../input/InputRange'
-import InputField from '../input/InputField'
-
-const FilterSubMenuElectronic = React.memo(({
-  id,
-  ...rest
-}) => {
-  const {selected, open} = useContext(filterMenuContext)
-  const visible = open && id === selected
-
-  return <FilterSubMenu id={id} {...rest}>
-    <InputGrid>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="electronic_properties"
-          visible={visible}
-          disableSearch
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputSection
-          section="results.properties.electronic.band_structure_electronic.band_gap"
-          visible={visible}
-        >
-          <InputField
-            quantity="results.properties.electronic.band_structure_electronic.band_gap.type"
-            visible={visible}
-            disableSearch
-          />
-          <InputRange
-            quantity="results.properties.electronic.band_structure_electronic.band_gap.value"
-            visible={visible}
-          />
-        </InputSection>
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputSection
-          section="results.properties.electronic.band_structure_electronic"
-          visible={visible}
-        >
-          <InputField
-            quantity="results.properties.electronic.band_structure_electronic.spin_polarized"
-            visible={visible}
-            disableSearch
-          />
-        </InputSection>
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputSection
-          section="results.properties.electronic.dos_electronic"
-          visible={visible}
-        >
-          <InputField
-            quantity="results.properties.electronic.dos_electronic.spin_polarized"
-            visible={visible}
-            disableSearch
-          />
-        </InputSection>
-      </InputGridItem>
-    </InputGrid>
-  </FilterSubMenu>
-})
-FilterSubMenuElectronic.propTypes = {
-  id: PropTypes.string
-}
-
-export default FilterSubMenuElectronic
diff --git a/gui/src/components/search/menus/FilterSubMenuElements.js b/gui/src/components/search/menus/FilterSubMenuElements.js
deleted file mode 100644
index 2d2ead4901..0000000000
--- a/gui/src/components/search/menus/FilterSubMenuElements.js
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright The NOMAD Authors.
- *
- * This file is part of NOMAD. See https://nomad-lab.eu for further info.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React, { useContext } from 'react'
-import PropTypes from 'prop-types'
-import { makeStyles } from '@material-ui/core/styles'
-import { FilterSubMenu, filterMenuContext } from './FilterMenu'
-import { InputGrid, InputGridItem } from '../input/InputGrid'
-import InputPeriodicTable from '../input/InputPeriodicTable'
-import InputField from '../input/InputField'
-import InputRange from '../input/InputRange'
-
-const useStyles = makeStyles(theme => ({
-  grid: {
-    marginTop: theme.spacing(2)
-  },
-  periodicTable: {
-    height: '30rem'
-  }
-}))
-
-const FilterSubMenuElements = React.memo(({
-  id,
-  ...rest
-}) => {
-  const {selected, open} = useContext(filterMenuContext)
-  const visible = open && id === selected
-  const styles = useStyles()
-
-  return <FilterSubMenu id={id} {...rest}>
-    <InputGrid className={styles.grid}>
-      <InputGridItem xs={12}>
-        <InputPeriodicTable
-          quantity="results.material.elements"
-          visible={visible}
-          className={styles.periodicTable}
-        />
-      </InputGridItem>
-      <InputGridItem xs={6}>
-        <InputField
-          quantity="results.material.chemical_formula_hill"
-          visible={visible}
-          disableOptions
-        />
-      </InputGridItem>
-      <InputGridItem xs={6}>
-        <InputField
-          quantity="results.material.chemical_formula_iupac"
-          visible={visible}
-          disableOptions
-        />
-      </InputGridItem>
-      <InputGridItem xs={6}>
-        <InputField
-          quantity="results.material.chemical_formula_reduced"
-          visible={visible}
-          disableOptions
-        />
-      </InputGridItem>
-      <InputGridItem xs={6}>
-        <InputField
-          quantity="results.material.chemical_formula_anonymous"
-          visible={visible}
-          placeholder="E.g. A2B, A3B2"
-          disableOptions
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputRange
-          quantity="results.material.n_elements"
-          visible={visible}
-          step={1}
-        />
-      </InputGridItem>
-    </InputGrid>
-  </FilterSubMenu>
-})
-FilterSubMenuElements.propTypes = {
-  id: PropTypes.string
-}
-
-export default FilterSubMenuElements
diff --git a/gui/src/components/search/menus/FilterSubMenuGW.js b/gui/src/components/search/menus/FilterSubMenuGW.js
deleted file mode 100644
index 55aa2c526f..0000000000
--- a/gui/src/components/search/menus/FilterSubMenuGW.js
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright The NOMAD Authors.
- *
- * This file is part of NOMAD. See https://nomad-lab.eu for further info.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React, { useContext } from 'react'
-import PropTypes from 'prop-types'
-import { FilterSubMenu, filterMenuContext } from './FilterMenu'
-import { InputGrid, InputGridItem } from '../input/InputGrid'
-import InputField from '../input/InputField'
-import { InputCheckboxValue } from '../input/InputCheckbox'
-
-const FilterSubMenuGW = React.memo(({
-  id,
-  ...rest
-}) => {
-  const {selected, open} = useContext(filterMenuContext)
-  const visible = open && id === selected
-
-  return <FilterSubMenu
-    id={id}
-    actions={<InputCheckboxValue
-      quantity="results.method.method_name"
-      value="GW"
-      description="Search GW entries"
-    />}
-    {...rest}>
-    <InputGrid>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.method.simulation.gw.type"
-          visible={visible}
-          xs={12}
-          disableSearch
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.method.simulation.gw.starting_point_type"
-          visible={visible}
-          xs={12}
-          disableSearch
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.method.simulation.gw.basis_set_type"
-          visible={visible}
-          xs={12}
-          disableSearch
-        />
-      </InputGridItem>
-    </InputGrid>
-  </FilterSubMenu>
-})
-FilterSubMenuGW.propTypes = {
-  id: PropTypes.string
-}
-
-export default FilterSubMenuGW
diff --git a/gui/src/components/search/menus/FilterSubMenuGeometryOptimization.js b/gui/src/components/search/menus/FilterSubMenuGeometryOptimization.js
deleted file mode 100644
index daf0e75bcb..0000000000
--- a/gui/src/components/search/menus/FilterSubMenuGeometryOptimization.js
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright The NOMAD Authors.
- *
- * This file is part of NOMAD. See https://nomad-lab.eu for further info.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React, { useContext } from 'react'
-import PropTypes from 'prop-types'
-import { FilterSubMenu, filterMenuContext } from './FilterMenu'
-import InputRange from '../input/InputRange'
-import InputSection from '../input/InputSection'
-import { InputCheckboxValue } from '../input/InputCheckbox'
-import { InputGrid, InputGridItem } from '../input/InputGrid'
-
-const FilterSubMenuGeometryOptimization = React.memo(({
-  id,
-  ...rest
-}) => {
-  const {selected, open} = useContext(filterMenuContext)
-  const visible = open && id === selected
-
-  return <FilterSubMenu
-    id={id}
-    actions={<InputCheckboxValue
-      quantity="results.properties.available_properties"
-      value="geometry_optimization"
-      description="Search entries with geometry optimization results"
-    />}
-    {...rest}>
-    <InputGrid>
-      <InputGridItem xs={12}>
-        <InputSection
-          section="results.properties.geometry_optimization"
-          visible={visible}
-          disableHeader
-        >
-          <InputRange
-            quantity="results.properties.geometry_optimization.final_energy_difference"
-            visible={visible}
-          />
-          <InputRange
-            quantity="results.properties.geometry_optimization.final_force_maximum"
-            visible={visible}
-          />
-          <InputRange
-            quantity="results.properties.geometry_optimization.final_displacement_maximum"
-            visible={visible}
-          />
-        </InputSection>
-      </InputGridItem>
-    </InputGrid>
-  </FilterSubMenu>
-})
-FilterSubMenuGeometryOptimization.propTypes = {
-  id: PropTypes.string
-}
-
-export default FilterSubMenuGeometryOptimization
diff --git a/gui/src/components/search/menus/FilterSubMenuMaterial.js b/gui/src/components/search/menus/FilterSubMenuMaterial.js
deleted file mode 100644
index 1ccc6fbef7..0000000000
--- a/gui/src/components/search/menus/FilterSubMenuMaterial.js
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright The NOMAD Authors.
- *
- * This file is part of NOMAD. See https://nomad-lab.eu for further info.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React, { useContext } from 'react'
-import PropTypes from 'prop-types'
-import { FilterSubMenu, filterMenuContext } from './FilterMenu'
-import { InputGrid, InputGridItem } from '../input/InputGrid'
-import InputField from '../input/InputField'
-
-const FilterSubMenuMaterial = React.memo(({
-  id,
-  ...rest
-}) => {
-  const {selected, open} = useContext(filterMenuContext)
-  const visible = open && id === selected
-
-  return <FilterSubMenu id={id} {...rest}>
-    <InputGrid>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.material.structural_type"
-          visible={visible}
-          disableSearch
-        />
-      </InputGridItem>
-    </InputGrid>
-  </FilterSubMenu>
-})
-FilterSubMenuMaterial.propTypes = {
-  id: PropTypes.string
-}
-
-export default FilterSubMenuMaterial
diff --git a/gui/src/components/search/menus/FilterSubMenuMechanical.js b/gui/src/components/search/menus/FilterSubMenuMechanical.js
deleted file mode 100644
index c8dfdb231d..0000000000
--- a/gui/src/components/search/menus/FilterSubMenuMechanical.js
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright The NOMAD Authors.
- *
- * This file is part of NOMAD. See https://nomad-lab.eu for further info.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React, { useContext } from 'react'
-import PropTypes from 'prop-types'
-import { FilterSubMenu, filterMenuContext } from './FilterMenu'
-import InputRange from '../input/InputRange'
-import InputField from '../input/InputField'
-import InputSection from '../input/InputSection'
-import { InputGrid, InputGridItem } from '../input/InputGrid'
-
-const FilterSubMenuMechanical = React.memo(({
-  id,
-  ...rest
-}) => {
-  const {selected, open} = useContext(filterMenuContext)
-  const visible = open && id === selected
-
-  return <FilterSubMenu id={id} {...rest}>
-    <InputGrid>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="mechanical_properties"
-          visible={visible}
-          disableSearch
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputSection
-          section="results.properties.mechanical.bulk_modulus"
-          visible={visible}
-        >
-          <InputField
-            quantity="results.properties.mechanical.bulk_modulus.type"
-            visible={visible}
-            initialSize={5}
-          />
-          <InputRange
-            quantity="results.properties.mechanical.bulk_modulus.value"
-            visible={visible}
-          />
-        </InputSection>
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputSection
-          section="results.properties.mechanical.shear_modulus"
-          visible={visible}
-        >
-          <InputField
-            quantity="results.properties.mechanical.shear_modulus.type"
-            visible={visible}
-            disableSearch
-          />
-          <InputRange
-            quantity="results.properties.mechanical.shear_modulus.value"
-            visible={visible}
-          />
-        </InputSection>
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputSection
-          section="results.properties.mechanical.energy_volume_curve"
-          visible={visible}
-        >
-          <InputField
-            quantity="results.properties.mechanical.energy_volume_curve.type"
-            visible={visible}
-            initialSize={5}
-          />
-        </InputSection>
-      </InputGridItem>
-    </InputGrid>
-  </FilterSubMenu>
-})
-FilterSubMenuMechanical.propTypes = {
-  id: PropTypes.string
-}
-
-export default FilterSubMenuMechanical
diff --git a/gui/src/components/search/menus/FilterSubMenuMethod.js b/gui/src/components/search/menus/FilterSubMenuMethod.js
deleted file mode 100644
index 1b12b8c636..0000000000
--- a/gui/src/components/search/menus/FilterSubMenuMethod.js
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright The NOMAD Authors.
- *
- * This file is part of NOMAD. See https://nomad-lab.eu for further info.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React, { useContext } from 'react'
-import PropTypes from 'prop-types'
-import { FilterSubMenu, filterMenuContext } from './FilterMenu'
-import { InputGrid, InputGridItem } from '../input/InputGrid'
-import InputField from '../input/InputField'
-
-const FilterSubMenuMethod = React.memo(({
-  id,
-  ...rest
-}) => {
-  const {selected, open} = useContext(filterMenuContext)
-  const visible = open && id === selected
-
-  return <FilterSubMenu id={id} {...rest}>
-    <InputGrid spacing={2}>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.method.simulation.program_name"
-          visible={visible}
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.method.simulation.program_version"
-          visible={visible}
-          disableOptions
-        />
-      </InputGridItem>
-    </InputGrid>
-  </FilterSubMenu>
-})
-FilterSubMenuMethod.propTypes = {
-  id: PropTypes.string
-}
-
-export default FilterSubMenuMethod
diff --git a/gui/src/components/search/menus/FilterSubMenuMolecularDynamics.js b/gui/src/components/search/menus/FilterSubMenuMolecularDynamics.js
deleted file mode 100644
index fe73d0cf47..0000000000
--- a/gui/src/components/search/menus/FilterSubMenuMolecularDynamics.js
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright The NOMAD Authors.
- *
- * This file is part of NOMAD. See https://nomad-lab.eu for further info.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React, { useContext } from 'react'
-import PropTypes from 'prop-types'
-import { FilterSubMenu, filterMenuContext } from './FilterMenu'
-import InputRange from '../input/InputRange'
-import InputField from '../input/InputField'
-import InputSection from '../input/InputSection'
-import { InputGrid, InputGridItem } from '../input/InputGrid'
-
-const FilterSubMenuMolecularDynamics = React.memo(({
-  id,
-  ...rest
-}) => {
-  const {selected} = useContext(filterMenuContext)
-  const visible = id === selected
-
-  return <FilterSubMenu id={id} {...rest}>
-    <InputGrid>
-      <InputGridItem xs={12}>
-        <InputSection
-          section="results.properties.thermodynamic.trajectory"
-          disableHeader
-          visible={visible}
-        >
-          <InputField
-            quantity="results.properties.thermodynamic.trajectory.available_properties"
-            visible={visible}
-            disableSearch
-            formatLabels
-          />
-          <InputField
-            quantity="results.properties.thermodynamic.trajectory.provenance.molecular_dynamics.ensemble_type"
-            disableSearch
-            visible={visible}
-          />
-          <InputRange
-            quantity="results.properties.thermodynamic.trajectory.provenance.molecular_dynamics.time_step"
-            visible={visible}
-          />
-        </InputSection>
-      </InputGridItem>
-    </InputGrid>
-  </FilterSubMenu>
-})
-FilterSubMenuMolecularDynamics.propTypes = {
-  id: PropTypes.string
-}
-
-export default FilterSubMenuMolecularDynamics
diff --git a/gui/src/components/search/menus/FilterSubMenuPrecision.js b/gui/src/components/search/menus/FilterSubMenuPrecision.js
deleted file mode 100644
index bcafd9f3ed..0000000000
--- a/gui/src/components/search/menus/FilterSubMenuPrecision.js
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright The NOMAD Authors.
- *
- * This file is part of NOMAD. See https://nomad-lab.eu for further info.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React, { useContext } from 'react'
-import PropTypes from 'prop-types'
-import { FilterSubMenu, filterMenuContext } from './FilterMenu'
-import { InputGrid, InputGridItem } from '../input/InputGrid'
-import InputField from '../input/InputField'
-import InputRange from '../input/InputRange'
-
-const FilterSubMenuPrecision = React.memo(({
-  id,
-  ...rest
-}) => {
-  const {selected, open} = useContext(filterMenuContext)
-  const visible = open && id === selected
-
-  return <FilterSubMenu id={id} {...rest}>
-    <InputGrid>
-      <InputGridItem xs={12}>
-        <InputRange
-          quantity="results.method.simulation.precision.k_line_density"
-          visible={visible}
-          xs={12}
-          disableSearch
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.method.simulation.precision.native_tier"
-          visible={visible}
-          xs={12}
-          disableOptions
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.method.simulation.precision.basis_set"
-          visible={visible}
-          xs={12}
-          disableSearch
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputRange
-          quantity="results.method.simulation.precision.planewave_cutoff"
-          visible={visible}
-          xs={12}
-          disableSearch
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputRange
-          quantity="results.method.simulation.precision.apw_cutoff"
-          visible={visible}
-          xs={12}
-          disableSearch
-        />
-      </InputGridItem>
-    </InputGrid>
-  </FilterSubMenu>
-})
-FilterSubMenuPrecision.propTypes = {
-  id: PropTypes.string
-}
-
-export default FilterSubMenuPrecision
diff --git a/gui/src/components/search/menus/FilterSubMenuSolarCell.js b/gui/src/components/search/menus/FilterSubMenuSolarCell.js
deleted file mode 100644
index 7bf32fe34f..0000000000
--- a/gui/src/components/search/menus/FilterSubMenuSolarCell.js
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright The NOMAD Authors.
- *
- * This file is part of NOMAD. See https://nomad-lab.eu for further info.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React, { useContext } from 'react'
-import PropTypes from 'prop-types'
-import { FilterSubMenu, filterMenuContext } from './FilterMenu'
-import { InputGrid, InputGridItem } from '../input/InputGrid'
-import InputRange from '../input/InputRange'
-import InputField from '../input/InputField'
-
-const FilterSubMenuSolarCell = React.memo(({
-  id,
-  ...rest
-}) => {
-  const {selected, open} = useContext(filterMenuContext)
-  const visible = open && id === selected
-
-  return <FilterSubMenu id={id} {...rest}>
-    <InputGrid>
-      <InputGridItem xs={12}>
-        <InputRange
-          quantity="results.properties.optoelectronic.solar_cell.efficiency"
-          visible={visible}
-        />
-        <InputRange
-          quantity="results.properties.optoelectronic.solar_cell.fill_factor"
-          visible={visible}
-        />
-        <InputRange
-          quantity="results.properties.optoelectronic.solar_cell.open_circuit_voltage"
-          visible={visible}
-        />
-        <InputRange
-          quantity="results.properties.optoelectronic.solar_cell.short_circuit_current_density"
-          visible={visible}
-        />
-        <InputRange
-          quantity="results.properties.optoelectronic.solar_cell.illumination_intensity"
-          visible={visible}
-        />
-        <InputRange
-          quantity="results.properties.optoelectronic.solar_cell.device_area"
-          visible={visible}
-        />
-        <InputField
-          quantity="results.properties.optoelectronic.solar_cell.device_architecture"
-          visible={visible}
-        />
-        <InputField
-          quantity="results.properties.optoelectronic.solar_cell.device_stack"
-          visible={visible}
-        />
-        <InputField
-          quantity="results.properties.optoelectronic.solar_cell.absorber"
-          visible={visible}
-        />
-        <InputField
-          quantity="results.properties.optoelectronic.solar_cell.absorber_fabrication"
-          visible={visible}
-        />
-        <InputField
-          quantity="results.properties.optoelectronic.solar_cell.electron_transport_layer"
-          visible={visible}
-        />
-        <InputField
-          quantity="results.properties.optoelectronic.solar_cell.hole_transport_layer"
-          visible={visible}
-        />
-        <InputField
-          quantity="results.properties.optoelectronic.solar_cell.substrate"
-          visible={visible}
-        />
-        <InputField
-          quantity="results.properties.optoelectronic.solar_cell.back_contact"
-          visible={visible}
-        />
-      </InputGridItem>
-    </InputGrid>
-  </FilterSubMenu>
-})
-FilterSubMenuSolarCell.propTypes = {
-  id: PropTypes.string
-}
-
-export default FilterSubMenuSolarCell
diff --git a/gui/src/components/search/menus/FilterSubMenuStructure.js b/gui/src/components/search/menus/FilterSubMenuStructure.js
deleted file mode 100644
index 37b3c0aa31..0000000000
--- a/gui/src/components/search/menus/FilterSubMenuStructure.js
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright The NOMAD Authors.
- *
- * This file is part of NOMAD. See https://nomad-lab.eu for further info.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React, { useContext } from 'react'
-import PropTypes from 'prop-types'
-import { FilterSubMenu, filterMenuContext } from './FilterMenu'
-import { InputGrid, InputGridItem } from '../input/InputGrid'
-import InputField from '../input/InputField'
-
-const FilterSubMenuStructure = React.memo(({
-  id,
-  ...rest
-}) => {
-  const {selected, open} = useContext(filterMenuContext)
-  const visible = open && id === selected
-
-  return <FilterSubMenu id={id} {...rest}>
-    <InputGrid>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.material.structural_type"
-          visible={visible}
-          disableSearch
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.material.symmetry.bravais_lattice"
-          visible={visible}
-          xs={6}
-          disableSearch
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.material.symmetry.crystal_system"
-          visible={visible}
-          xs={12}
-          disableSearch
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.material.symmetry.space_group_symbol"
-          visible={visible}
-          disableOptions
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.material.symmetry.structure_name"
-          visible={visible}
-          initialSize={5}
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.material.symmetry.strukturbericht_designation"
-          visible={visible}
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.material.symmetry.point_group"
-          visible={visible}
-          disableOptions
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.material.symmetry.hall_symbol"
-          visible={visible}
-          disableOptions
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.material.symmetry.prototype_aflow_id"
-          visible={visible}
-          disableOptions
-        />
-      </InputGridItem>
-    </InputGrid>
-  </FilterSubMenu>
-})
-FilterSubMenuStructure.propTypes = {
-  id: PropTypes.string
-}
-
-export default FilterSubMenuStructure
diff --git a/gui/src/components/search/menus/FilterSubMenuTB.js b/gui/src/components/search/menus/FilterSubMenuTB.js
deleted file mode 100644
index cd6b4aa936..0000000000
--- a/gui/src/components/search/menus/FilterSubMenuTB.js
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright The NOMAD Authors.
- *
- * This file is part of NOMAD. See https://nomad-lab.eu for further info.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React, { useContext } from 'react'
-import PropTypes from 'prop-types'
-import { FilterSubMenu, filterMenuContext } from './FilterMenu'
-import { InputGrid, InputGridItem } from '../input/InputGrid'
-import InputField from '../input/InputField'
-import { InputCheckboxValue } from '../input/InputCheckbox'
-
-const FilterSubMenuTB = React.memo(({
-  id,
-  ...rest
-}) => {
-  const {selected, open} = useContext(filterMenuContext)
-  const visible = open && id === selected
-
-  return <FilterSubMenu
-    id={id}
-    actions={<InputCheckboxValue
-      quantity="results.method.method_name"
-      value="TB"
-      description="Search TB entries"
-    />}
-    {...rest}>
-    <InputGrid>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.method.simulation.tb.type"
-          visible={visible}
-          xs={12}
-          disableSearch
-        />
-      </InputGridItem>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="results.method.simulation.tb.localization_type"
-          visible={visible}
-          xs={12}
-          disableSearch
-        />
-      </InputGridItem>
-    </InputGrid>
-  </FilterSubMenu>
-})
-FilterSubMenuTB.propTypes = {
-  id: PropTypes.string
-}
-
-export default FilterSubMenuTB
diff --git a/gui/src/components/search/menus/FilterSubMenuVibrational.js b/gui/src/components/search/menus/FilterSubMenuVibrational.js
deleted file mode 100644
index c4b30868fb..0000000000
--- a/gui/src/components/search/menus/FilterSubMenuVibrational.js
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright The NOMAD Authors.
- *
- * This file is part of NOMAD. See https://nomad-lab.eu for further info.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React, { useContext } from 'react'
-import PropTypes from 'prop-types'
-import { FilterSubMenu, filterMenuContext } from './FilterMenu'
-import { InputGrid, InputGridItem } from '../input/InputGrid'
-import InputField from '../input/InputField'
-
-const FilterSubMenuElectronic = React.memo(({
-  id,
-  ...rest
-}) => {
-  const {selected, open} = useContext(filterMenuContext)
-  const visible = open && id === selected
-
-  return <FilterSubMenu id={id} {...rest}>
-    <InputGrid>
-      <InputGridItem xs={12}>
-        <InputField
-          quantity="vibrational_properties"
-          visible={visible}
-          disableSearch
-        />
-      </InputGridItem>
-    </InputGrid>
-  </FilterSubMenu>
-})
-FilterSubMenuElectronic.propTypes = {
-  id: PropTypes.string
-}
-
-export default FilterSubMenuElectronic
diff --git a/gui/src/components/search/menus/Menu.js b/gui/src/components/search/menus/Menu.js
new file mode 100644
index 0000000000..9b133914d5
--- /dev/null
+++ b/gui/src/components/search/menus/Menu.js
@@ -0,0 +1,489 @@
+/*
+ * Copyright The NOMAD Authors.
+ *
+ * This file is part of NOMAD. See https://nomad-lab.eu for further info.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React, { useState, useEffect, isValidElement, Children, useCallback, useContext } from 'react'
+import PropTypes from 'prop-types'
+import clsx from 'clsx'
+import { makeStyles, useTheme } from '@material-ui/core/styles'
+import {
+  List,
+  ListItem,
+  ListItemText,
+  ListItemIcon,
+  Paper,
+  Typography,
+  Checkbox,
+  MenuItem as MenuItemMUI,
+  FormControlLabel
+} from '@material-ui/core'
+import { delay } from '../../../utils'
+import NavigateNextIcon from '@material-ui/icons/NavigateNext'
+import ArrowForwardIcon from '@material-ui/icons/ArrowForward'
+import Scrollable from '../../visualization/Scrollable'
+import { Action, Actions, ActionHeader } from '../../Actions'
+import FilterTitle from '../FilterTitle'
+import { useSearchContext } from '../SearchContext'
+
+// The menu animations use a transition on the 'transform' property. Notice that
+// animating 'transform' instead of e.g. the 'left' property is much more
+// performant. We also hint the browser that the transform property will be
+// animated using the 'will-change' property: this will pre-optimize the element
+// for animation when possible (the recommendation is to remove/add it when
+// needed, but in this case we keep it on constantly).
+//
+// The menu widths are hardcoded. We need the widths to perform the close
+// animation. Another option would be to use useLayoutEffect to determine the
+// sizes of the components dynamically, but this seems to be quite a bit less
+// responsive compared to hardcoding the values.
+
+export const menuContext = React.createContext()
+export const paddingHorizontal = 1.5
+const collapseWidth = '3rem'
+
+/**
+ * Provides a context for a menu.
+ */
+const useMenuStyles = (props) => makeStyles(theme => {
+  return {
+    root: {
+      boxSizing: 'border-box',
+      display: 'flex',
+      height: '100%',
+      flexDirection: 'column',
+      '-webkit-transform': `translateX(-${props.width})`,
+      'transform': `translateX(-${props.width})`,
+      width: `${props.width}`,
+      transition: `transform 225ms`,
+      willChange: 'transform',
+      visibility: 'hidden'
+    },
+    menu: {
+      position: 'absolute',
+      right: 0,
+      top: 0,
+      bottom: 0,
+      boxSizing: 'border-box',
+      display: 'flex',
+      flexDirection: 'column',
+      marginTop: '1px',
+      width: `${props.width}`
+    },
+    open: {
+      '-webkit-transform': 'none',
+      transform: 'none'
+    },
+    container: {
+      height: '100%'
+    },
+    containerCollapsed: {
+      width: collapseWidth
+    },
+    collapsed: {
+      '-webkit-transform': `translateX(calc(-${props.width} + ${collapseWidth}))`,
+      'transform': `translateX(calc(-${props.width} + 50px))`
+    },
+    visible: {
+      visibility: 'visible'
+    }
+  }
+})
+export const Menu = React.memo(({
+  size,
+  open,
+  collapsed,
+  onCollapsedChanged,
+  subMenuOpen,
+  visible,
+  onOpenChange,
+  selected,
+  onSelectedChange,
+  className,
+  children
+}) => {
+  const width = {
+    'xs': '17rem',
+    'sm': '21rem',
+    'md': '25rem',
+    'lg': '29rem',
+    'xl': '33rem',
+    'xxl': '45rem'
+  }[size] || size || '21rem'
+  const styles = useMenuStyles({width})()
+
+  return <div className={clsx(styles.container, collapsed && styles.containerCollapsed)}>
+    <Paper
+      elevation={open ? 4 : 0}
+      className={clsx(className, styles.root, open && styles.open, collapsed && styles.collapsed, visible && styles.visible)}
+    >
+      <menuContext.Provider value={{
+        collapsed,
+        selected,
+        setSelected: onSelectedChange,
+        setCollapsed: onCollapsedChanged,
+        subMenuOpen,
+        open,
+        setOpen: onOpenChange,
+        size
+      }}>
+      {children}
+      </menuContext.Provider>
+    </Paper>
+  </div>
+})
+Menu.propTypes = {
+  size: PropTypes.string,
+  open: PropTypes.bool,
+  collapsed: PropTypes.bool,
+  onCollapsedChanged: PropTypes.func,
+  subMenuOpen: PropTypes.bool,
+  visible: PropTypes.bool,
+  onOpenChange: PropTypes.func,
+  selected: PropTypes.number,
+  onSelectedChange: PropTypes.func,
+  className: PropTypes.string,
+  children: PropTypes.node
+}
+
+/**
+ * Header for filter menus. Contains panel actions and an overline text.
+ */
+const useMenuHeaderStyles = makeStyles(theme => {
+  return {
+    root: {
+      height: theme.spacing(3),
+      paddingBottom: theme.spacing(1.2),
+      paddingTop: theme.spacing(1.4),
+      paddingLeft: theme.spacing(paddingHorizontal),
+      paddingRight: theme.spacing(paddingHorizontal),
+      display: 'flex',
+      flexDirection: 'column',
+      justifyContent: 'center',
+      zIndex: 4,
+      backgroundColor: theme.palette.background.paper,
+      boxShadow: `1px 0px 0px 0px #e0e0e0`
+    },
+    title: {
+      display: 'flex',
+      alignItems: 'center',
+      fontSize: '0.90rem'
+    }
+  }
+})
+export const MenuHeader = React.memo(({
+  title,
+  actions,
+  className,
+  'data-testid': testID
+}) => {
+  const styles = useMenuHeaderStyles()
+  const { collapsed, setCollapsed } = useContext(menuContext)
+
+  return <div className={clsx(className, styles.root)} data-testid={testID}>
+    <Actions>
+      <ActionHeader>
+        <Typography className={styles.title} variant="button">{title}</Typography>
+      </ActionHeader>
+      {collapsed
+        ? <Action
+          tooltip={'Show menu'}
+          onClick={() => setCollapsed(false)}
+        >
+          <ArrowForwardIcon fontSize="small"/>
+        </Action>
+        : actions
+      }
+    </Actions>
+  </div>
+})
+
+MenuHeader.propTypes = {
+  overlineTitle: PropTypes.string,
+  title: PropTypes.string,
+  topAction: PropTypes.node,
+  actions: PropTypes.node,
+  className: PropTypes.string,
+  'data-testid': PropTypes.string
+}
+
+/**
+ * Menu content that is wrapped in a customized scrollable area.
+ */
+const useMenuContentStyles = makeStyles(theme => {
+  return {
+    root: {
+      boxSizing: 'border-box',
+      display: 'flex',
+      flexDirection: 'column',
+      width: '100%',
+      height: '100%',
+      position: 'relative',
+      backgroundColor: theme.palette.background.paper,
+      zIndex: 3
+    },
+    headerTextVertical: {
+      display: 'flex',
+      alignItems: 'center',
+      position: 'absolute',
+      right: '0.07rem',
+      top: '2.5rem',
+      transform: 'rotate(90deg)'
+    },
+    menu: {
+      position: 'absolute',
+      right: 0,
+      top: 0,
+      bottom: 0,
+      left: 0,
+      boxSizing: 'border-box'
+    },
+    menuBorder: {
+      boxShadow: `1px 0px 0px 0px #e0e0e0`
+    },
+    button: {
+      marginRight: 0,
+      '-webkit-transform': 'none',
+      transform: 'none',
+      transition: 'transform 250ms',
+      willChange: 'transform'
+    },
+    overflow: {
+      overflow: 'visible'
+    },
+    list: {
+      paddingTop: 0
+    },
+    container: {
+      display: 'flex',
+      flexDirection: 'column',
+      height: '100%'
+    },
+    content: {
+      flex: 1,
+      minHeight: 0
+    },
+    hidden: {
+      visibility: 'hidden'
+    },
+    collapsedText: {
+      display: 'flex',
+      alignItems: 'center',
+      position: 'absolute',
+      right: '0.07rem',
+      top: 0,
+      height: collapseWidth,
+      transform: 'rotate(90deg)'
+    }
+
+  }
+})
+export const MenuContent = React.memo(({
+  className,
+  children
+}) => {
+  const styles = useMenuContentStyles()
+  const { open, collapsed } = useContext(menuContext)
+  // Unfortunately the ClickAwayListener does not play nicely together with
+  // Menus/Select/Popper. When using Portals, the clicks are registered wrong.
+  // When Portals are disabled (disablePortal), their positioning goes haywire.
+  // The clicks outside are thus detected by individual event listeners that
+  // toggle the menu state.
+  return <div className={clsx(className, styles.root)}>
+    <div className={clsx(styles.menu, open && styles.menuBorder)}>
+      <div className={styles.container}>
+        <div className={clsx(styles.content, collapsed && styles.hidden)}>
+          <Scrollable>
+            <List dense className={styles.list}>
+              {children}
+            </List>
+          </Scrollable>
+        </div>
+      {collapsed && <Typography
+          className={clsx(styles.collapsedText)}
+          variant="button"
+        >Filters
+        </Typography>
+      }
+      </div>
+    </div>
+  </div>
+})
+MenuContent.propTypes = {
+  className: PropTypes.string,
+  children: PropTypes.node
+}
+
+/**
+ * Menu submenus. Ensures that submenus are correctly placed underneath the
+ * menu and their loading is delayed.
+ */
+const useMenuSubMenusStyles = makeStyles(theme => {
+  return {
+    root: {
+      position: 'absolute',
+      top: '0',
+      bottom: '0',
+      left: '100%'
+    },
+    relative: {
+      position: 'relative',
+      width: '100%',
+      height: '100%'
+    },
+    absolute: {
+      position: 'absolute',
+      top: 0,
+      bottom: 0,
+      right: 0,
+      left: 0
+    }
+  }
+})
+export const MenuSubMenus = React.memo(({
+  className,
+  children
+}) => {
+  const styles = useMenuSubMenusStyles()
+  const [loaded, setLoaded] = useState(false)
+
+  // Rendering the submenus is delayed on the event queue: this makes loading
+  // the search page more responsive by first loading everything else.
+  useEffect(() => {
+    delay(() => { setLoaded(true) })
+  }, [])
+
+  return loaded
+    ? <div className={clsx(className, styles.root)}>
+    <div className={styles.relatives}>
+      {Children.map(children, (child) => {
+          if (isValidElement(child)) {
+            return (
+              <div className={styles.absolute}>
+                <child.type {...child.props}/>
+              </div>
+            )
+          }
+      })}
+    </div>
+  </div>
+  : null
+})
+MenuSubMenus.propTypes = {
+  className: PropTypes.string,
+  children: PropTypes.node
+}
+
+/**
+ * Menu item.
+ */
+const levelIndent = 1.8
+const useMenuItemStyles = makeStyles(theme => {
+  return {
+    root: {
+    },
+    listIcon: {
+      fontsize: '1rem',
+      minWidth: '1.5rem'
+    },
+    arrow: {
+      marginLeft: theme.spacing(1),
+      fontSize: '1.5rem'
+    },
+    listItem: {
+      paddingTop: theme.spacing(0.75),
+      paddingBottom: theme.spacing(0.75),
+      position: 'relative'
+    },
+    actions: {
+      display: 'flex',
+      flexDirection: 'column'
+    }
+  }
+})
+export const MenuItem = React.memo(({
+  id,
+  title,
+  disableButton,
+  level
+}) => {
+  const styles = useMenuItemStyles()
+  const theme = useTheme()
+  const { selected, setSelected, subMenuOpen } = useContext(menuContext)
+  const opened = subMenuOpen && id === selected
+  const handleClick = useCallback(() => {
+    if (disableButton) return
+    setSelected?.(id)
+  }, [disableButton, id, setSelected])
+
+  return <div className={styles.root}>
+    {(title || !disableButton) &&
+    <ListItem
+      button={!disableButton}
+      className={styles.listItem}
+      onClick={handleClick}
+    >
+      {title && <ListItemText
+        style={{marginLeft: theme.spacing(level * levelIndent)}}
+        primaryTypographyProps={{
+          color: opened ? 'primary' : 'initial'
+        }}
+        primary={<FilterTitle label={title}/>}
+        data-testid={`menu-item-label-${id}`}
+      />}
+      {!disableButton && <ListItemIcon className={styles.listIcon}>
+        <NavigateNextIcon color={opened ? 'primary' : 'action'} className={styles.arrow}/>
+      </ListItemIcon>}
+    </ListItem>}
+  </div>
+})
+
+MenuItem.propTypes = {
+  id: PropTypes.number,
+  title: PropTypes.string,
+  disableButton: PropTypes.bool,
+  level: PropTypes.number
+}
+MenuItem.defaultProps = {
+  level: 0
+}
+
+/**
+ * Settings for a menu.
+ */
+export const MenuSettings = React.memo(() => {
+  const {
+    useIsStatisticsEnabled,
+    useSetIsStatisticsEnabled
+  } = useSearchContext()
+  const [isStatisticsEnabled, setIsStatisticsEnabled] = [
+    useIsStatisticsEnabled(),
+    useSetIsStatisticsEnabled()
+  ]
+
+  const handleStatsChange = useCallback((event, value) => {
+    setIsStatisticsEnabled(value)
+  }, [setIsStatisticsEnabled])
+
+  return <MenuItemMUI>
+    <FormControlLabel
+      control={<Checkbox
+        checked={isStatisticsEnabled}
+        onChange={handleStatsChange}
+      />}
+      label="Show advanced statistics"
+    />
+  </MenuItemMUI>
+})
diff --git a/gui/src/components/search/widgets/Dashboard.js b/gui/src/components/search/widgets/Dashboard.js
index 7a6f526e67..7350853bc6 100644
--- a/gui/src/components/search/widgets/Dashboard.js
+++ b/gui/src/components/search/widgets/Dashboard.js
@@ -107,11 +107,9 @@ const Dashboard = React.memo(() => {
         xl: {...layout},
         xxl: {...layout}
       },
-      // x: {scale: 'linear'},
-      // y: {scale: 'linear'},
       size: 1000,
       autorange: true,
-      type: 'scatterplot'
+      type: 'scatter_plot'
     }
     addWidget(id, value)
   }, [addWidget])
@@ -133,8 +131,8 @@ const Dashboard = React.memo(() => {
         xxl: {...layout}
       },
       scale: 'linear',
-      quantity: 'results.material.elements',
-      type: 'periodictable'
+      search_quantity: 'results.material.elements',
+      type: 'periodic_table'
     }
     addWidget(id, value)
   }, [addWidget])
@@ -255,8 +253,10 @@ const Dashboard = React.memo(() => {
     {widgets && Object.entries(widgets).map(([id, value]) => {
       if (!value.editing) return null
       const comp = {
-        scatterplot: <WidgetScatterPlotEdit key={id} widget={value}/>,
-        periodictable: <WidgetPeriodicTableEdit key={id} {...value}/>,
+        scatter_plot: <WidgetScatterPlotEdit key={id} widget={value}/>,
+        scatterplot: <WidgetScatterPlotEdit key={id} widget={value}/>, // Deprecated misspelling
+        periodic_table: <WidgetPeriodicTableEdit key={id} {...value}/>,
+        periodictable: <WidgetPeriodicTableEdit key={id} {...value}/>, // Deprecated misspelling
         histogram: <WidgetHistogramEdit key={id} widget={value}/>,
         terms: <WidgetTermsEdit key={id} {...value}/>
       }[value.type]
@@ -283,8 +283,10 @@ DashboardAction.propTypes = {
 }
 
 const schemas = {
-  scatterplot: schemaWidgetScatterPlot,
-  periodictable: schemaWidgetPeriodicTable,
+  scatterplot: schemaWidgetScatterPlot, // Deprecated misspelling
+  scatter_plot: schemaWidgetScatterPlot,
+  periodictable: schemaWidgetPeriodicTable, // Deprecated misspelling
+  periodic_table: schemaWidgetPeriodicTable,
   histogram: schemaWidgetHistogram,
   terms: schemaWidgetTerms
 }
diff --git a/gui/src/components/search/widgets/Dashboard.spec.js b/gui/src/components/search/widgets/Dashboard.spec.js
index 51e32cdec9..bf71438e7a 100644
--- a/gui/src/components/search/widgets/Dashboard.spec.js
+++ b/gui/src/components/search/widgets/Dashboard.spec.js
@@ -46,7 +46,7 @@ describe('displaying an initial widget and removing it', () => {
       'terms',
       {
         type: 'terms',
-        quantity: 'results.material.structural_type',
+        search_quantity: 'results.material.structural_type',
         scale: 'linear',
         editing: false,
         visible: true,
@@ -70,7 +70,7 @@ describe('displaying an initial widget and removing it', () => {
       {
         type: 'histogram',
         title: 'Test title',
-        x: {quantity: 'results.material.n_elements'},
+        x: {search_quantity: 'results.material.n_elements'},
         y: {scale: 'linear'},
         editing: false,
         visible: true,
@@ -85,13 +85,13 @@ describe('displaying an initial widget and removing it', () => {
       async (widget, loaded) => await expectInputRange(widget, loaded, true, true)
     ],
     [
-      'scatterplot',
+      'scatter_plot',
       {
-        type: 'scatterplot',
+        type: 'scatter_plot',
         title: 'Test title',
-        x: {quantity: 'results.properties.optoelectronic.solar_cell.open_circuit_voltage'},
-        y: {quantity: 'results.properties.optoelectronic.solar_cell.efficiency'},
-        markers: {color: {quantity: 'results.properties.optoelectronic.solar_cell.short_circuit_current_density'}},
+        x: {search_quantity: 'results.properties.optoelectronic.solar_cell.open_circuit_voltage'},
+        y: {search_quantity: 'results.properties.optoelectronic.solar_cell.efficiency'},
+        markers: {color: {search_quantity: 'results.properties.optoelectronic.solar_cell.short_circuit_current_density'}},
         size: 1000,
         autorange: true,
         editing: false,
@@ -107,10 +107,10 @@ describe('displaying an initial widget and removing it', () => {
       async (widget, loaded) => await expectWidgetScatterPlot(widget, loaded)
     ],
     [
-      'periodictable',
+      'periodic_table',
       {
-        type: 'periodictable',
-        quantity: 'results.material.elements',
+        type: 'periodic_table',
+        search_quantity: 'results.material.elements',
         scale: 'linear',
         editing: false,
         visible: true,
@@ -123,7 +123,7 @@ describe('displaying an initial widget and removing it', () => {
         }
       },
       async (widget, loaded) => {
-        await expectInputHeader(widget.quantity)
+        await expectInputHeader(widget.search_quantity)
         // TODO: For some reason this test works out fine locally, but always
         // fails in the CI. Could not be resolved even by making the tests wait
         // much longer.
@@ -148,7 +148,7 @@ describe('displaying an initial widget and removing it', () => {
     // Remove widget, check that it is gone. A test id is used to fetch the
     // remove button since it is an icon that may appear in several locations.
     const removeButton = screen.getByTestId(`0-remove-widget`)
-    const label = widget.title || defaultFilterData[widget.quantity].label
+    const label = widget.title || defaultFilterData[widget.search_quantity].label
     expect(screen.queryByText(label, {exact: false})).toBeInTheDocument()
     await userEvent.click(removeButton)
     expect(screen.queryByText(label, {exact: false})).not.toBeInTheDocument()
diff --git a/gui/src/components/search/widgets/Widget.js b/gui/src/components/search/widgets/Widget.js
index a6be7bb705..a12454779a 100644
--- a/gui/src/components/search/widgets/Widget.js
+++ b/gui/src/components/search/widgets/Widget.js
@@ -114,13 +114,13 @@ export const schemaAxisBase = object({
   scale: string().nullable()
 })
 export const schemaAxis = object({
-  quantity: string().required(),
+  search_quantity: string().required(),
   unit: string().nullable(),
   title: string().nullable(),
   scale: string().nullable()
 })
 export const schemaAxisOptional = object({
-  quantity: string().nullable(),
+  search_quantity: string().nullable(),
   unit: string().nullable(),
   title: string().nullable(),
   scale: string().nullable()
diff --git a/gui/src/components/search/widgets/WidgetGrid.js b/gui/src/components/search/widgets/WidgetGrid.js
index 0966315a39..9a375334f1 100644
--- a/gui/src/components/search/widgets/WidgetGrid.js
+++ b/gui/src/components/search/widgets/WidgetGrid.js
@@ -294,8 +294,10 @@ const WidgetGrid = React.memo(({
         .sort((a, b) => b[1].index - a[1].index)
         .map(([id, value]) => {
           const Comp = {
-            scatterplot: WidgetScatterPlot,
-            periodictable: WidgetPeriodicTable,
+            scatter_plot: WidgetScatterPlot,
+            scatterplot: WidgetScatterPlot, // Deprecated misspelling
+            periodic_table: WidgetPeriodicTable,
+            periodictable: WidgetPeriodicTable, // Deprecated misspelling
             histogram: WidgetHistogram,
             terms: WidgetTerms
           }[value.type]
diff --git a/gui/src/components/search/widgets/WidgetHeader.js b/gui/src/components/search/widgets/WidgetHeader.js
index 66958a682a..aa29873959 100644
--- a/gui/src/components/search/widgets/WidgetHeader.js
+++ b/gui/src/components/search/widgets/WidgetHeader.js
@@ -90,6 +90,7 @@ const WidgetHeader = React.memo(({
         onMouseUp={handleMouseUp}
       >
         <FilterTitle
+          variant="subtitle2"
           quantity={quantity}
           label={label}
           description={description}
diff --git a/gui/src/components/search/widgets/WidgetHistogram.js b/gui/src/components/search/widgets/WidgetHistogram.js
index 1f54766891..bf61008469 100644
--- a/gui/src/components/search/widgets/WidgetHistogram.js
+++ b/gui/src/components/search/widgets/WidgetHistogram.js
@@ -20,10 +20,8 @@ import PropTypes from 'prop-types'
 import { useSearchContext } from '../SearchContext'
 import { Widget } from './Widget'
 import { ActionCheckbox, ActionSelect } from '../../Actions'
-import { Range } from '../input/InputRange'
-import { scales } from '../../plotting/common'
-import {getDisplayLabel} from '../../../utils'
-import { Unit } from '../../units/Unit'
+import { Histogram } from '../input/InputHistogram'
+import { getAxisConfig, scales } from '../../plotting/common'
 import { useUnitContext } from '../../units/UnitContext'
 
 /**
@@ -39,7 +37,7 @@ export const WidgetHistogram = React.memo((
   y,
   nbins,
   autorange,
-  showinput,
+  show_input,
   className
 }) => {
   const { filterData, useSetWidget } = useSearchContext()
@@ -47,21 +45,7 @@ export const WidgetHistogram = React.memo((
   const setWidget = useSetWidget(id)
 
   // Create final axis config for the plot
-  const xAxis = useMemo(() => {
-    const xFilter = filterData[x.quantity]
-    const xTitle = x.title || getDisplayLabel(xFilter)
-    const xType = xFilter?.dtype
-    const xUnit = x.unit
-      ? new Unit(x.unit)
-      : new Unit(xFilter.unit || 'dimensionless').toSystem(units)
-
-    return {
-      ...x,
-      title: xTitle,
-      unit: xUnit,
-      dtype: xType
-    }
-  }, [filterData, x, units])
+  const xAxis = useMemo(() => getAxisConfig(x, filterData, units), [x, filterData, units])
 
   const handleEdit = useCallback(() => {
     setWidget(old => { return {...old, editing: true } })
@@ -92,14 +76,15 @@ export const WidgetHistogram = React.memo((
       />
     </>}
   >
-    <Range
-      xAxis={xAxis}
-      yAxis={y}
+    <Histogram
+      x={xAxis}
+      y={y}
       visible={true}
       nBins={nbins}
       anchored={true}
       autorange={autorange}
-      showinput={showinput}
+      showInput={show_input}
+      showStatistics={true}
       aggId={id}
     />
   </Widget>
@@ -113,6 +98,6 @@ WidgetHistogram.propTypes = {
   y: PropTypes.object,
   nbins: PropTypes.number,
   autorange: PropTypes.bool,
-  showinput: PropTypes.bool,
+  show_input: PropTypes.bool,
   className: PropTypes.string
 }
diff --git a/gui/src/components/search/widgets/WidgetHistogram.spec.js b/gui/src/components/search/widgets/WidgetHistogram.spec.js
new file mode 100644
index 0000000000..a5a405dd4c
--- /dev/null
+++ b/gui/src/components/search/widgets/WidgetHistogram.spec.js
@@ -0,0 +1,61 @@
+/*
+ * Copyright The NOMAD Authors.
+ *
+ * This file is part of NOMAD. See https://nomad-lab.eu for further info.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react'
+import { renderSearchEntry, expectWidgetHistogram } from '../conftest.spec'
+import { WidgetHistogram } from './WidgetHistogram'
+
+// Mock the resize observer that defines the widget size
+jest.mock('react-resize-detector', () => {
+  return {useResizeDetector: () => {
+    return {height: 400, width: 400, ref: undefined}
+  }}
+})
+
+describe.only('test custom axis titles', () => {
+  test.each([
+    ['no unit', {x: {title: 'My Title', search_quantity: 'results.material.n_elements'}}, 'My Title'],
+    ['with unit', {x: {title: 'My Title', search_quantity: 'results.properties.geometry_optimization.final_energy_difference'}}, 'My Title (eV)']
+  ])('%s', async (name, config, title) => {
+    const configFinal = {
+      id: '0',
+      y: {scale: 'linear'},
+      ...config
+    }
+    renderSearchEntry(<WidgetHistogram {...configFinal} />)
+    await expectWidgetHistogram(configFinal)
+  })
+})
+
+describe('test custom axis units', () => {
+  test.each([
+    ['x', {x: {unit: 'Ha', search_quantity: 'results.properties.geometry_optimization.final_energy_difference'}}, 'Final energy difference (Ha)'],
+    ['y', {y: {unit: 'Ha', search_quantity: 'results.properties.geometry_optimization.final_energy_difference'}}, 'Final energy difference (Ha)'],
+    ['color', {markers: {color: {unit: 'Ha', search_quantity: 'results.properties.geometry_optimization.final_energy_difference'}}}, 'Final energy difference (Ha)']
+  ])('%s', async (name, config, title) => {
+    const configFinal = {
+      id: '0',
+      scale: 'linear',
+      x: {search_quantity: 'results.material.n_elements'},
+      y: {search_quantity: 'results.material.n_elements'},
+      markers: {color: {search_quantity: 'results.material.n_elements'}},
+      ...config
+    }
+    renderSearchEntry(<WidgetHistogram {...configFinal} />)
+    await expectWidgetHistogram(configFinal)
+  })
+})
diff --git a/gui/src/components/search/widgets/WidgetHistogramEdit.js b/gui/src/components/search/widgets/WidgetHistogramEdit.js
index 5b1bbe1f5d..d70f3e4e58 100644
--- a/gui/src/components/search/widgets/WidgetHistogramEdit.js
+++ b/gui/src/components/search/widgets/WidgetHistogramEdit.js
@@ -95,9 +95,9 @@ export const WidgetHistogramEdit = React.memo(({widget}) => {
       // Check for missing values. This check is required because there is no
       // value set when a new widget is created, and pressing the done button
       // without filling a value should raise an error.
-      const xEmpty = isEmptyString(settings?.x?.quantity)
+      const xEmpty = isEmptyString(settings?.x?.search_quantity)
       if (xEmpty) {
-        handleErrorQuantity('x.quantity', 'Please specify a value.')
+        handleErrorQuantity('x.search_quantity', 'Please specify a value.')
       }
 
       if (!independentErrors && !xEmpty) {
@@ -116,20 +116,20 @@ export const WidgetHistogramEdit = React.memo(({widget}) => {
       <WidgetEditGroup title="x axis">
         <WidgetEditOption>
           <InputMetainfo
-            label="quantity"
-            value={settings.x?.quantity}
-            error={errors['x.quantity']}
-            onChange={(value) => handleChange('x.quantity', value)}
-            onAccept={(value) => handleAcceptQuantity('x.quantity', value)}
-            onSelect={(value) => handleAcceptQuantity('x.quantity', value)}
-            onError={(value) => handleErrorQuantity('x.quantity', value)}
+            label="Search quantity"
+            value={settings.x?.search_quantity}
+            error={errors['x.search_quantity']}
+            onChange={(value) => handleChange('x.search_quantity', value)}
+            onAccept={(value) => handleAcceptQuantity('x.search_quantity', value)}
+            onSelect={(value) => handleAcceptQuantity('x.search_quantity', value)}
+            onError={(value) => handleErrorQuantity('x.search_quantity', value)}
             dtypes={dtypes}
             dtypesRepeatable={dtypes}
           />
         </WidgetEditOption>
         <WidgetEditOption>
           <InputTextField
-            label="title"
+            label="Title"
             fullWidth
             value={settings.x?.title}
             onChange={(event) => handleChange('x.title', event.target.value)}
@@ -137,14 +137,14 @@ export const WidgetHistogramEdit = React.memo(({widget}) => {
         </WidgetEditOption>
         <WidgetEditOption>
           <UnitInput
-            label='unit'
+            label='Unit'
             value={settings.x?.unit}
             onChange={(value) => handleChange('x.unit', value)}
             onSelect={(value) => handleAccept('x.unit', value)}
             onAccept={(value) => handleAccept('x.unit', value)}
             error={errors['x.unit']}
             onError={(value) => handleError('x.unit', value)}
-            dimension={dimensions['x.quantity'] || null}
+            dimension={dimensions['x.search_quantity'] || null}
             optional
             disableGroup
           />
@@ -155,7 +155,7 @@ export const WidgetHistogramEdit = React.memo(({widget}) => {
           <TextField
             select
             fullWidth
-            label="scale"
+            label="Scale"
             variant="filled"
             value={settings.y?.scale}
             onChange={(event) => { handleChange('y.scale', event.target.value) }}
@@ -169,7 +169,7 @@ export const WidgetHistogramEdit = React.memo(({widget}) => {
       <WidgetEditGroup title="general">
         <WidgetEditOption>
           <InputTextField
-            label="title"
+            label="Title"
             fullWidth
             value={settings?.title}
             onChange={(event) => handleChange('title', event.target.value)}
@@ -200,7 +200,7 @@ export const WidgetHistogramEdit = React.memo(({widget}) => {
         </WidgetEditOption>
         <WidgetEditOption>
           <FormControlLabel
-            control={<Checkbox checked={settings.showinput} onChange={(event, value) => handleChange('showinput', value)}/>}
+            control={<Checkbox checked={settings.show_input} onChange={(event, value) => handleChange('show_input', value)}/>}
             label='Show input fields'
           />
         </WidgetEditOption>
@@ -218,5 +218,5 @@ export const schemaWidgetHistogram = schemaWidget.shape({
   y: schemaAxisBase.required('Y-axis configuration is required.'),
   nbins: number().integer().required(),
   autorange: bool(),
-  showinput: bool()
+  show_input: bool()
 })
diff --git a/gui/src/components/search/widgets/WidgetHistogramEdit.spec.js b/gui/src/components/search/widgets/WidgetHistogramEdit.spec.js
index c449b45009..f32cd626e5 100644
--- a/gui/src/components/search/widgets/WidgetHistogramEdit.spec.js
+++ b/gui/src/components/search/widgets/WidgetHistogramEdit.spec.js
@@ -24,9 +24,9 @@ import { WidgetHistogramEdit } from './WidgetHistogramEdit'
 describe('test edit dialog error messages', () => {
   test.each([
     ['missing x', {x: {}}, 'Please specify a value.'],
-    ['unavailable x', {x: {quantity: 'results.material.not_a_quantity'}}, 'The quantity "results.material.not_a_quantity" is not available.'],
-    ['invalid x unit', {x: {quantity: 'results.material.topology.cell.a', unit: 'nounit'}}, 'Unit "nounit" not found.'],
-    ['incompatible x unit', {x: {quantity: 'results.material.topology.cell.a', unit: 'joule'}}, 'Unit "joule" is incompatible with dimension "length".']
+    ['unavailable x', {x: {search_quantity: 'results.material.not_a_quantity'}}, 'The quantity "results.material.not_a_quantity" is not available.'],
+    ['invalid x unit', {x: {search_quantity: 'results.material.topology.cell.a', unit: 'nounit'}}, 'Unit "nounit" not found.'],
+    ['incompatible x unit', {x: {search_quantity: 'results.material.topology.cell.a', unit: 'joule'}}, 'Unit "joule" is incompatible with dimension "length".']
   ])('%s', async (name, config, error) => {
     const finalConfig = {
       id: '0',
diff --git a/gui/src/components/search/widgets/WidgetPeriodicTable.js b/gui/src/components/search/widgets/WidgetPeriodicTable.js
index 5055fc0fe4..9a5f711a45 100644
--- a/gui/src/components/search/widgets/WidgetPeriodicTable.js
+++ b/gui/src/components/search/widgets/WidgetPeriodicTable.js
@@ -24,8 +24,12 @@ import { Widget, schemaWidget } from './Widget'
 import { ActionSelect } from '../../Actions'
 import { WidgetEditDialog, WidgetEditGroup, WidgetEditOption } from './WidgetEdit'
 import { InputTextField } from '../input/InputText'
+import { InputMetainfo } from '../input/InputMetainfo'
 import { PeriodicTable } from '../input/InputPeriodicTable'
 import { scales } from '../../plotting/common'
+import { DType } from '../../../utils'
+
+const dtypes = new Set([DType.String, DType.Enum])
 
 /**
  * Displays a periodic table as a widget.
@@ -35,7 +39,7 @@ export const WidgetPeriodicTable = React.memo((
   id,
   title,
   description,
-  quantity,
+  search_quantity,
   scale,
   className
 }) => {
@@ -52,7 +56,7 @@ export const WidgetPeriodicTable = React.memo((
 
   return <Widget
     id={id}
-    quantity={quantity}
+    quantity={search_quantity}
     title={title}
     description={description}
     onEdit={handleEdit}
@@ -67,10 +71,9 @@ export const WidgetPeriodicTable = React.memo((
     }
   >
     <PeriodicTable
-      quantity={quantity}
+      quantity={search_quantity}
       scale={scale}
       anchored={true}
-      disableStatistics={true}
       visible={true}
       // Can't use the same aggregation identifier as the periodic table in the
       // filter menu: due to rendering order the aggregation may otherwise get
@@ -84,7 +87,7 @@ WidgetPeriodicTable.propTypes = {
   id: PropTypes.string.isRequired,
   title: PropTypes.string,
   description: PropTypes.string,
-  quantity: PropTypes.string,
+  search_quantity: PropTypes.string,
   scale: PropTypes.string,
   className: PropTypes.string
 }
@@ -143,6 +146,19 @@ export const WidgetPeriodicTableEdit = React.memo((props) => {
         error={hasError}
       >
       <WidgetEditGroup title="Elements">
+        <WidgetEditOption>
+          <InputMetainfo
+            label="Search quantity"
+            value={settings.search_quantity}
+            error={errors.search_quantity}
+            onChange={(value) => handleChange('search_quantity', value)}
+            onSelect={(value) => handleAccept('search_quantity', value)}
+            onError={(value) => handleError('search_quantity', value)}
+            dtypes={dtypes}
+            dtypesRepeatable={dtypes}
+            disableNonAggregatable
+          />
+        </WidgetEditOption>
         <WidgetEditOption>
           <TextField
             select
@@ -164,7 +180,7 @@ export const WidgetPeriodicTableEdit = React.memo((props) => {
       <WidgetEditGroup title="General">
         <WidgetEditOption>
           <InputTextField
-            label="title"
+            label="Title"
             fullWidth
             value={settings?.title}
             onChange={(event) => handleChange('title', event.target.value)}
@@ -184,6 +200,6 @@ WidgetPeriodicTableEdit.propTypes = {
 }
 
 export const schemaWidgetPeriodicTable = schemaWidget.shape({
-  quantity: string().required('Quantity is required.'),
+  search_quantity: string().required('Search quantity is required.'),
   scale: string().required('Scale is required.')
 })
diff --git a/gui/src/components/search/widgets/WidgetScatterPlot.js b/gui/src/components/search/widgets/WidgetScatterPlot.js
index 84efcd71be..7f56fefdeb 100644
--- a/gui/src/components/search/widgets/WidgetScatterPlot.js
+++ b/gui/src/components/search/widgets/WidgetScatterPlot.js
@@ -34,10 +34,11 @@ import { Action, ActionCheckbox } from '../../Actions'
 import { CropFree, PanTool, Fullscreen, Replay } from '@material-ui/icons'
 import { autorangeDescription } from './WidgetHistogram'
 import { styled } from '@material-ui/core/styles'
-import {DType, parseJMESPath, getDisplayLabel} from '../../../utils'
+import {DType, parseJMESPath} from '../../../utils'
 import { Quantity } from '../../units/Quantity'
 import { Unit } from '../../units/Unit'
 import { useUnitContext } from '../../units/UnitContext'
+import { getAxisConfig } from '../../plotting/common'
 
 const StyledToggleButtonGroup = styled(ToggleButtonGroup)(({ theme }) => ({
   '& .MuiToggleButtonGroup-grouped': {
@@ -93,52 +94,38 @@ export const WidgetScatterPlot = React.memo((
   const { useSetWidget, useHits, filterData, useSetFilter } = useSearchContext()
 
   // Parse additional JMESPath config
-  const [xParsed, yParsed, colorParsed, error] = useMemo(() => {
-    const xParsed = parseJMESPath(x?.quantity)
-    const yParsed = parseJMESPath(y?.quantity)
-    const colorParsed = markers?.color?.quantity ? parseJMESPath(markers.color.quantity) : {}
+  const [xParsed, yParsed, colorParsed, discrete, error] = useMemo(() => {
+    const xParsed = parseJMESPath(x?.search_quantity)
+    const yParsed = parseJMESPath(y?.search_quantity)
+    const colorParsed = markers?.color?.search_quantity ? parseJMESPath(markers.color.search_quantity) : {}
+    const discrete = colorParsed?.quantity && new Set([DType.String, DType.Enum]).has(filterData[colorParsed.quantity]?.dtype)
     if (xParsed.error || yParsed.error || colorParsed.error) {
-      return [{}, {}, {}, 'Invalid JMESPath query, please check your syntax.']
+      return [{}, {}, {}, undefined, 'Invalid JMESPath query, please check your syntax.']
     }
-    return [xParsed, yParsed, colorParsed, undefined]
-  }, [markers?.color?.quantity, x?.quantity, y?.quantity])
+    return [xParsed, yParsed, colorParsed, discrete, undefined]
+  }, [markers?.color?.search_quantity, x?.search_quantity, y?.search_quantity, filterData])
 
-  // Parse units
-  const {unitXObj, unitYObj, unitColorObj, displayUnitX, displayUnitY, displayUnitColor, discrete} = useMemo(() => {
+  // Get storage unit for API communication
+  const {storageUnitX, storageUnitY, storageUnitColor} = useMemo(() => {
     if (error) return {}
-    const unitXObj = new Unit(filterData[xParsed.quantity].unit || 'dimensionless')
-    const unitYObj = new Unit(filterData[yParsed.quantity].unit || 'dimensionless')
-    const unitColorObj = new Unit(filterData[colorParsed?.quantity]?.unit || 'dimensionless')
-    const displayUnitX = x.unit ? new Unit(x.unit) : unitXObj.toSystem(units)
-    const displayUnitY = y.unit ? new Unit(y.unit) : unitYObj.toSystem(units)
-    const displayUnitColor = markers?.color?.unit ? new Unit(markers?.color?.unit) : unitColorObj.toSystem(units)
-    const discrete = colorParsed?.quantity && new Set([DType.String, DType.Enum]).has(filterData[colorParsed.quantity]?.dtype)
-    return {unitXObj, unitYObj, unitColorObj, displayUnitX, displayUnitY, displayUnitColor, discrete}
-  }, [filterData, x.unit, xParsed.quantity, y.unit, yParsed.quantity, markers?.color?.unit, colorParsed?.quantity, units, error])
+    const storageUnitX = new Unit(filterData[xParsed.quantity].unit || 'dimensionless')
+    const storageUnitY = new Unit(filterData[yParsed.quantity].unit || 'dimensionless')
+    const storageUnitColor = new Unit(filterData[colorParsed?.quantity]?.unit || 'dimensionless')
+    return {storageUnitX, storageUnitY, storageUnitColor}
+  }, [filterData, xParsed.quantity, yParsed.quantity, colorParsed?.quantity, error])
 
   // Create final axis config for the plot
   const {xAxis, yAxis, colorAxis} = useMemo(() => {
-    if (error) return {}
-    const xFilter = filterData[xParsed.quantity]
-    const yFilter = filterData[yParsed.quantity]
-    const colorFilter = filterData[colorParsed.quantity]
-    const xTitle = x.title || xFilter?.label || getDisplayLabel(xFilter)
-    const yTitle = y.title || yFilter?.label || getDisplayLabel(yFilter)
-    const xType = xFilter?.dtype
-    const yType = yFilter?.dtype
-    const colorTitle = markers?.color?.title || colorFilter?.label || getDisplayLabel(colorFilter)
-    const unitLabelX = displayUnitX.label()
-    const unitLabelY = displayUnitY.label()
-    const unitLabelColor = displayUnitColor.label()
+    if (error) return {xAxis: {}, yAxis: {}, colorAxis: {}}
     return {
-      xAxis: {...x, ...xParsed, title: xTitle, unit: unitLabelX, type: xType},
-      yAxis: {...y, ...yParsed, title: yTitle, unit: unitLabelY, type: yType},
-      colorAxis: markers?.color ? {...markers.color, ...colorParsed, title: colorTitle, unit: unitLabelColor} : {}
+      xAxis: getAxisConfig(x, filterData, units),
+      yAxis: getAxisConfig(y, filterData, units),
+      colorAxis: markers?.color ? getAxisConfig(markers.color, filterData, units) : {}
     }
-  }, [colorParsed, displayUnitColor, displayUnitX, displayUnitY, filterData, markers?.color, x, xParsed, y, yParsed, error])
+  }, [error, filterData, markers.color, x, units, y])
 
-  const setXFilter = useSetFilter(xParsed.quantity)
-  const setYFilter = useSetFilter(yParsed.quantity)
+  const setXFilter = useSetFilter(xAxis.search_quantity)
+  const setYFilter = useSetFilter(yAxis.search_quantity)
 
   const setWidget = useSetWidget(id)
   const pagination = useMemo(() => ({
@@ -279,16 +266,16 @@ export const WidgetScatterPlot = React.memo((
     if (!dataRaw) return
     const x = xAxis.type === DType.Timestamp
       ? dataRaw.x
-      : new Quantity(dataRaw.x, unitXObj).to(displayUnitX).value()
+      : new Quantity(dataRaw.x, storageUnitX).to(xAxis.unit).value()
     const y = yAxis.type === DType.Timestamp
       ? dataRaw.y
-      : new Quantity(dataRaw.y, unitYObj).to(displayUnitY).value()
+      : new Quantity(dataRaw.y, storageUnitY).to(yAxis.unit).value()
     const color = dataRaw.color && (discrete
       ? dataRaw.color
-      : new Quantity(dataRaw.color, unitColorObj).to(displayUnitColor).value()
+      : new Quantity(dataRaw.color, storageUnitColor).to(colorAxis.unit).value()
     )
     return {x, y, color, id: dataRaw.id}
-  }, [dataRaw, displayUnitColor, displayUnitX, displayUnitY, unitColorObj, unitXObj, unitYObj, discrete, xAxis, yAxis])
+  }, [dataRaw, xAxis.type, xAxis.unit, storageUnitX, yAxis.type, yAxis.unit, storageUnitY, discrete, storageUnitColor, colorAxis.unit])
 
   const handleEdit = useCallback(() => {
     setWidget(old => { return {...old, editing: true } })
@@ -315,15 +302,15 @@ export const WidgetScatterPlot = React.memo((
     const range = data?.range
     if (!range) return
     setXFilter({
-      gte: new Quantity(range.x[0], displayUnitX),
-      lte: new Quantity(range.x[1], displayUnitX)
+      gte: new Quantity(range.x[0], xAxis.unit),
+      lte: new Quantity(range.x[1], xAxis.unit)
     })
     setYFilter({
-      gte: new Quantity(range.y[0], displayUnitY),
-      lte: new Quantity(range.y[1], displayUnitY)
+      gte: new Quantity(range.y[0], yAxis.unit),
+      lte: new Quantity(range.y[1], yAxis.unit)
     })
     onSelected?.(data)
-  }, [onSelected, setXFilter, setYFilter, displayUnitX, displayUnitY])
+  }, [setXFilter, xAxis.unit, setYFilter, yAxis.unit, onSelected])
 
   const handleDeselect = useCallback(() => {
     onSelected?.(undefined)
diff --git a/gui/src/components/search/widgets/WidgetScatterPlot.spec.js b/gui/src/components/search/widgets/WidgetScatterPlot.spec.js
index ee7dce6f5a..161994bbd9 100644
--- a/gui/src/components/search/widgets/WidgetScatterPlot.spec.js
+++ b/gui/src/components/search/widgets/WidgetScatterPlot.spec.js
@@ -96,9 +96,9 @@ describe('test different combinations of x/y/color produced with JMESPath', () =
     const config = {
       id: '0',
       scale: 'linear',
-      x: {quantity: x},
-      y: {quantity: y},
-      markers: {color: {quantity: color}}
+      x: {search_quantity: x},
+      y: {search_quantity: y},
+      markers: {color: {search_quantity: color}}
     }
     renderSearchEntry(<WidgetScatterPlot {...config} />)
     await expectWidgetScatterPlot(config, false)
@@ -107,19 +107,19 @@ describe('test different combinations of x/y/color produced with JMESPath', () =
 
 describe('test custom axis titles', () => {
   test.each([
-    ['x, no unit', {x: {title: 'My Title', quantity: 'results.material.n_elements'}}, 'My Title'],
-    ['y, no unit', {y: {title: 'My Title', quantity: 'results.material.n_elements'}}, 'My Title'],
-    ['color, no unit', {markers: {color: {title: 'My Title', quantity: 'results.material.n_elements'}}}, 'My Title'],
-    ['x, with unit', {x: {title: 'My Title', quantity: 'results.properties.geometry_optimization.final_energy_difference'}}, 'My Title (eV)'],
-    ['y, with unit', {y: {title: 'My Title', quantity: 'results.properties.geometry_optimization.final_energy_difference'}}, 'My Title (eV)'],
-    ['color, with unit', {markers: {color: {title: 'My Title', quantity: 'results.properties.geometry_optimization.final_energy_difference'}}}, 'My Title (eV)']
+    ['x, no unit', {x: {title: 'My Title', search_quantity: 'results.material.n_elements'}}, 'My Title'],
+    ['y, no unit', {y: {title: 'My Title', search_quantity: 'results.material.n_elements'}}, 'My Title'],
+    ['color, no unit', {markers: {color: {title: 'My Title', search_quantity: 'results.material.n_elements'}}}, 'My Title'],
+    ['x, with unit', {x: {title: 'My Title', search_quantity: 'results.properties.geometry_optimization.final_energy_difference'}}, 'My Title (eV)'],
+    ['y, with unit', {y: {title: 'My Title', search_quantity: 'results.properties.geometry_optimization.final_energy_difference'}}, 'My Title (eV)'],
+    ['color, with unit', {markers: {color: {title: 'My Title', search_quantity: 'results.properties.geometry_optimization.final_energy_difference'}}}, 'My Title (eV)']
   ])('%s', async (name, config, title) => {
     const configFinal = {
       id: '0',
       scale: 'linear',
-      x: {quantity: 'results.material.n_elements'},
-      y: {quantity: 'results.material.n_elements'},
-      markers: {color: {quantity: 'results.material.n_elements'}},
+      x: {search_quantity: 'results.material.n_elements'},
+      y: {search_quantity: 'results.material.n_elements'},
+      markers: {color: {search_quantity: 'results.material.n_elements'}},
       ...config
     }
     renderSearchEntry(<WidgetScatterPlot {...configFinal} />)
@@ -129,16 +129,16 @@ describe('test custom axis titles', () => {
 
 describe('test custom axis units', () => {
   test.each([
-    ['x', {x: {unit: 'Ha', quantity: 'results.properties.geometry_optimization.final_energy_difference'}}, 'Final energy difference (Ha)'],
-    ['y', {y: {unit: 'Ha', quantity: 'results.properties.geometry_optimization.final_energy_difference'}}, 'Final energy difference (Ha)'],
-    ['color', {markers: {color: {unit: 'Ha', quantity: 'results.properties.geometry_optimization.final_energy_difference'}}}, 'Final energy difference (Ha)']
+    ['x', {x: {unit: 'Ha', search_quantity: 'results.properties.geometry_optimization.final_energy_difference'}}, 'Final energy difference (Ha)'],
+    ['y', {y: {unit: 'Ha', search_quantity: 'results.properties.geometry_optimization.final_energy_difference'}}, 'Final energy difference (Ha)'],
+    ['color', {markers: {color: {unit: 'Ha', search_quantity: 'results.properties.geometry_optimization.final_energy_difference'}}}, 'Final energy difference (Ha)']
   ])('%s', async (name, config, title) => {
     const configFinal = {
       id: '0',
       scale: 'linear',
-      x: {quantity: 'results.material.n_elements'},
-      y: {quantity: 'results.material.n_elements'},
-      markers: {color: {quantity: 'results.material.n_elements'}},
+      x: {search_quantity: 'results.material.n_elements'},
+      y: {search_quantity: 'results.material.n_elements'},
+      markers: {color: {search_quantity: 'results.material.n_elements'}},
       ...config
     }
     renderSearchEntry(<WidgetScatterPlot {...configFinal} />)
@@ -149,17 +149,17 @@ describe('test custom axis units', () => {
 describe('test different colors', () => {
   test.each([
     ['empty', undefined, undefined, []],
-    ['scalar integer', 'results.material.n_elements', {quantity: 'results.material.n_elements'}, []],
-    ['scalar float', 'results.properties.geometry_optimization.final_energy_difference', {quantity: 'results.properties.geometry_optimization.final_energy_difference'}, []],
+    ['scalar integer', 'results.material.n_elements', {search_quantity: 'results.material.n_elements'}, []],
+    ['scalar float', 'results.properties.geometry_optimization.final_energy_difference', {search_quantity: 'results.properties.geometry_optimization.final_energy_difference'}, []],
     ['scalar string', 'results.material.chemical_formula_hill', undefined, ['Si2', 'CO2']],
     ['array string', 'results.material.elements', undefined, ['Si', 'C, O']]
   ])('%s', async (name, axis, colorTitle, legend) => {
     const config = {
       id: '0',
       scale: 'linear',
-      x: {quantity: 'results.material.n_elements'},
-      y: {quantity: 'results.material.n_elements'},
-      markers: {color: {quantity: axis}}
+      x: {search_quantity: 'results.material.n_elements'},
+      y: {search_quantity: 'results.material.n_elements'},
+      markers: {color: {search_quantity: axis}}
     }
     renderSearchEntry(<WidgetScatterPlot {...config} />)
     await expectWidgetScatterPlot(config, false, colorTitle, legend)
@@ -173,9 +173,9 @@ describe('test error messages', () => {
     const config = {
       id: '0',
       scale: 'linear',
-      x: {quantity: axis},
-      y: {quantity: axis},
-      markers: {color: {quantity: axis}}
+      x: {search_quantity: axis},
+      y: {search_quantity: axis},
+      markers: {color: {search_quantity: axis}}
     }
     renderSearchEntry(<WidgetScatterPlot {...config} />)
     screen.getByText(message, {exact: false})
diff --git a/gui/src/components/search/widgets/WidgetScatterPlotEdit.js b/gui/src/components/search/widgets/WidgetScatterPlotEdit.js
index 04ecdf4175..61a6991e5f 100644
--- a/gui/src/components/search/widgets/WidgetScatterPlotEdit.js
+++ b/gui/src/components/search/widgets/WidgetScatterPlotEdit.js
@@ -102,13 +102,13 @@ export const WidgetScatterPlotEdit = React.memo(({widget}) => {
       // Check for missing values. This check is required because there is no
       // value set when a new widget is created, and pressing the done button
       // without filling a value should raise an error.
-      const xEmpty = isEmptyString(settings?.x?.quantity)
+      const xEmpty = isEmptyString(settings?.x?.search_quantity)
       if (xEmpty) {
-        handleErrorQuantity('x.quantity', 'Please specify a value.')
+        handleErrorQuantity('x.search_quantity', 'Please specify a value.')
       }
-      const yEmpty = isEmptyString(settings?.y?.quantity)
+      const yEmpty = isEmptyString(settings?.y?.search_quantity)
       if (yEmpty) {
-        handleErrorQuantity('y.quantity', 'Please specify a value.')
+        handleErrorQuantity('y.search_quantity', 'Please specify a value.')
       }
 
       if (!independentErrors && !xEmpty && !yEmpty) {
@@ -127,20 +127,20 @@ export const WidgetScatterPlotEdit = React.memo(({widget}) => {
       <WidgetEditGroup title="x axis">
         <WidgetEditOption>
           <InputJMESPath
-            label="quantity"
-            value={settings.x?.quantity}
-            onChange={(value) => handleChange('x.quantity', value)}
-            onSelect={(value) => handleAcceptQuantity('x.quantity', value)}
-            onAccept={(value) => handleAcceptQuantity('x.quantity', value)}
-            error={errors['x.quantity']}
-            onError={(value) => handleErrorQuantity('x.quantity', value)}
+            label="Search quantity"
+            value={settings.x?.search_quantity}
+            onChange={(value) => handleChange('x.search_quantity', value)}
+            onSelect={(value) => handleAcceptQuantity('x.search_quantity', value)}
+            onAccept={(value) => handleAcceptQuantity('x.search_quantity', value)}
+            error={errors['x.search_quantity']}
+            onError={(value) => handleErrorQuantity('x.search_quantity', value)}
             dtypes={dtypesNumeric}
             dtypesRepeatable={dtypesNumeric}
           />
         </WidgetEditOption>
         <WidgetEditOption>
           <InputTextField
-            label="title"
+            label="Title"
             fullWidth
             value={settings.x?.title}
             onChange={(event) => handleChange('x.title', event.target.value)}
@@ -148,14 +148,14 @@ export const WidgetScatterPlotEdit = React.memo(({widget}) => {
         </WidgetEditOption>
         <WidgetEditOption>
           <UnitInput
-            label='unit'
+            label='Unit'
             value={settings.x?.unit}
             onChange={(value) => handleChange('x.unit', value)}
             onSelect={(value) => handleAccept('x.unit', value)}
             onAccept={(value) => handleAccept('x.unit', value)}
             error={errors['x.unit']}
             onError={(value) => handleError('x.unit', value)}
-            dimension={dimensions['x.quantity'] || null}
+            dimension={dimensions['x.search_quantity'] || null}
             optional
             disableGroup
           />
@@ -164,7 +164,7 @@ export const WidgetScatterPlotEdit = React.memo(({widget}) => {
           <TextField
             select
             fullWidth
-            label="scale"
+            label="Scale"
             variant="filled"
             value={settings.x?.scale}
             onChange={(event) => { handleChange('x.scale', event.target.value) }}
@@ -178,20 +178,20 @@ export const WidgetScatterPlotEdit = React.memo(({widget}) => {
       <WidgetEditGroup title="y axis">
         <WidgetEditOption>
           <InputJMESPath
-            label="quantity"
-            value={settings.y?.quantity}
-            onChange={(value) => handleChange('y.quantity', value)}
-            onSelect={(value) => handleAcceptQuantity('y.quantity', value)}
-            onAccept={(value) => handleAcceptQuantity('y.quantity', value)}
-            error={errors['y.quantity']}
-            onError={(value) => handleErrorQuantity('y.quantity', value)}
+            label="Search quantity"
+            value={settings.y?.search_quantity}
+            onChange={(value) => handleChange('y.search_quantity', value)}
+            onSelect={(value) => handleAcceptQuantity('y.search_quantity', value)}
+            onAccept={(value) => handleAcceptQuantity('y.search_quantity', value)}
+            error={errors['y.search_quantity']}
+            onError={(value) => handleErrorQuantity('y.search_quantity', value)}
             dtypes={dtypesNumeric}
             dtypesRepeatable={dtypesNumeric}
           />
         </WidgetEditOption>
         <WidgetEditOption>
           <InputTextField
-            label="title"
+            label="Title"
             fullWidth
             value={settings.y?.title}
             onChange={(event) => handleChange('y.title', event.target.value)}
@@ -199,14 +199,14 @@ export const WidgetScatterPlotEdit = React.memo(({widget}) => {
         </WidgetEditOption>
         <WidgetEditOption>
           <UnitInput
-            label='unit'
+            label='Unit'
             value={settings.y?.unit}
             onChange={(value) => handleChange('y.unit', value)}
             onSelect={(value) => handleAccept('y.unit', value)}
             onAccept={(value) => handleAccept('y.unit', value)}
             error={errors['y.unit']}
             onError={(value) => handleError('y.unit', value)}
-            dimension={dimensions['y.quantity'] || null}
+            dimension={dimensions['y.search_quantity'] || null}
             optional
             disableGroup
           />
@@ -215,7 +215,7 @@ export const WidgetScatterPlotEdit = React.memo(({widget}) => {
           <TextField
             select
             fullWidth
-            label="scale"
+            label="Scale"
             variant="filled"
             value={settings.y?.scale}
             onChange={(event) => { handleChange('y.scale', event.target.value) }}
@@ -229,13 +229,13 @@ export const WidgetScatterPlotEdit = React.memo(({widget}) => {
       <WidgetEditGroup title="marker color">
         <WidgetEditOption>
           <InputJMESPath
-            label="quantity"
-            value={settings?.markers?.color?.quantity}
-            onChange={(value) => handleChange('markers.color.quantity', value)}
-            onSelect={(value) => handleAcceptQuantity('markers.color.quantity', value)}
-            onAccept={(value) => handleAcceptQuantity('markers.color.quantity', value)}
-            error={errors['markers.color.quantity']}
-            onError={(value) => handleErrorQuantity('markers.color.quantity', value)}
+            label="Search quantity"
+            value={settings?.markers?.color?.search_quantity}
+            onChange={(value) => handleChange('markers.color.search_quantity', value)}
+            onSelect={(value) => handleAcceptQuantity('markers.color.search_quantity', value)}
+            onAccept={(value) => handleAcceptQuantity('markers.color.search_quantity', value)}
+            error={errors['markers.color.search_quantity']}
+            onError={(value) => handleErrorQuantity('markers.color.search_quantity', value)}
             dtypes={dtypesColor}
             dtypesRepeatable={dtypesColor}
             optional
@@ -243,7 +243,7 @@ export const WidgetScatterPlotEdit = React.memo(({widget}) => {
         </WidgetEditOption>
         <WidgetEditOption>
           <InputTextField
-            label="title"
+            label="Title"
             fullWidth
             value={settings.markers?.color?.title}
             onChange={(event) => handleChange('markers.color.title', event.target.value)}
@@ -251,23 +251,23 @@ export const WidgetScatterPlotEdit = React.memo(({widget}) => {
         </WidgetEditOption>
         <WidgetEditOption>
           <UnitInput
-            label='unit'
+            label='Unit'
             value={settings.markers?.color?.unit}
             onChange={(value) => handleChange('markers.color.unit', value)}
             onSelect={(value) => handleAccept('markers.color.unit', value)}
             onAccept={(value) => handleAccept('markers.color.unit', value)}
             error={errors['markers.color.unit']}
             onError={(value) => handleError('markers.color.unit', value)}
-            dimension={dimensions['markers.color.quantity'] || null}
+            dimension={dimensions['markers.color.search_quantity'] || null}
             optional
             disableGroup
           />
         </WidgetEditOption>
       </WidgetEditGroup>
-      <WidgetEditGroup title="general">
+      <WidgetEditGroup title="General">
         <WidgetEditOption>
           <InputTextField
-            label="title"
+            label="Title"
             fullWidth
             value={settings?.title}
             onChange={(event) => handleChange('title', event.target.value)}
@@ -296,8 +296,8 @@ WidgetScatterPlotEdit.propTypes = {
 }
 
 export const schemaWidgetScatterPlot = schemaWidget.shape({
-  x: schemaAxis.required('Quantity for the x axis is required.'),
-  y: schemaAxis.required('Quantity for the y axis is required.'),
+  x: schemaAxis.required('Search quantity for the x axis is required.'),
+  y: schemaAxis.required('Search quantity for the y axis is required.'),
   markers: schemaMarkers,
   size: number().integer().required('Size is required.'),
   autorange: bool()
diff --git a/gui/src/components/search/widgets/WidgetScatterPlotEdit.spec.js b/gui/src/components/search/widgets/WidgetScatterPlotEdit.spec.js
index 7f8d458f4a..6f7bd36ade 100644
--- a/gui/src/components/search/widgets/WidgetScatterPlotEdit.spec.js
+++ b/gui/src/components/search/widgets/WidgetScatterPlotEdit.spec.js
@@ -23,23 +23,23 @@ import { WidgetScatterPlotEdit } from './WidgetScatterPlotEdit'
 
 describe('test edit dialog error messages', () => {
   test.each([
-    ['missing x', {x: {quantity: 'results.material.n_elements'}}, 'Please specify a value.'],
-    ['missing y', {y: {quantity: 'results.material.n_elements'}}, 'Please specify a value.'],
-    ['unavailable x', {x: {quantity: 'results.material.not_a_quantity'}}, 'The quantity "results.material.not_a_quantity" is not available.'],
-    ['unavailable y', {y: {quantity: 'results.material.not_a_quantity'}}, 'The quantity "results.material.not_a_quantity" is not available.'],
-    ['unavailable color', {markers: {color: {quantity: 'results.material.not_a_quantity'}}}, 'The quantity "results.material.not_a_quantity" is not available.'],
-    ['invalid jmespath x', {x: {quantity: 'results.material.n_elements[*'}}, 'Invalid JMESPath query, please check your syntax.'],
-    ['invalid jmespath y', {y: {quantity: 'results.material.n_elements[*'}}, 'Invalid JMESPath query, please check your syntax.'],
-    ['invalid jmespath color', {markers: {color: {quantity: 'results.material.n_elements[*'}}}, 'Invalid JMESPath query, please check your syntax.'],
-    ['no jmespath for repeating x', {x: {quantity: 'results.material.topology.cell.a'}}, 'The quantity "results.material.topology.cell.a" is contained in at least one repeatable section. Please use JMESPath syntax to select one or more target sections.'],
-    ['no jmespath for repeating y', {y: {quantity: 'results.material.topology.cell.a'}}, 'The quantity "results.material.topology.cell.a" is contained in at least one repeatable section. Please use JMESPath syntax to select one or more target sections.'],
-    ['no jmespath for repeating color', {markers: {color: {quantity: 'results.material.topology.cell.a'}}}, 'The quantity "results.material.topology.cell.a" is contained in at least one repeatable section. Please use JMESPath syntax to select one or more target sections.'],
-    ['invalid x unit', {x: {quantity: 'results.material.topology[0].cell.a', unit: 'nounit'}}, 'Unit "nounit" not found.'],
-    ['invalid y unit', {y: {quantity: 'results.material.topology[0].cell.a', unit: 'nounit'}}, 'Unit "nounit" not found.'],
-    ['invalid color unit', {markers: {color: {quantity: 'results.material.topology[0].cell.a', unit: 'nounit'}}}, 'Unit "nounit" not found.'],
-    ['incompatible x unit', {x: {quantity: 'results.material.topology[0].cell.a', unit: 'joule'}}, 'Unit "joule" is incompatible with dimension "length".'],
-    ['incompatible y unit', {y: {quantity: 'results.material.topology[0].cell.a', unit: 'joule'}}, 'Unit "joule" is incompatible with dimension "length".'],
-    ['incompatible color unit', {markers: {color: {quantity: 'results.material.topology[0].cell.a', unit: 'joule'}}}, 'Unit "joule" is incompatible with dimension "length".']
+    ['missing x', {x: {search_quantity: 'results.material.n_elements'}}, 'Please specify a value.'],
+    ['missing y', {y: {search_quantity: 'results.material.n_elements'}}, 'Please specify a value.'],
+    ['unavailable x', {x: {search_quantity: 'results.material.not_a_quantity'}}, 'The quantity "results.material.not_a_quantity" is not available.'],
+    ['unavailable y', {y: {search_quantity: 'results.material.not_a_quantity'}}, 'The quantity "results.material.not_a_quantity" is not available.'],
+    ['unavailable color', {markers: {color: {search_quantity: 'results.material.not_a_quantity'}}}, 'The quantity "results.material.not_a_quantity" is not available.'],
+    ['invalid jmespath x', {x: {search_quantity: 'results.material.n_elements[*'}}, 'Invalid JMESPath query, please check your syntax.'],
+    ['invalid jmespath y', {y: {search_quantity: 'results.material.n_elements[*'}}, 'Invalid JMESPath query, please check your syntax.'],
+    ['invalid jmespath color', {markers: {color: {search_quantity: 'results.material.n_elements[*'}}}, 'Invalid JMESPath query, please check your syntax.'],
+    ['no jmespath for repeating x', {x: {search_quantity: 'results.material.topology.cell.a'}}, 'The quantity "results.material.topology.cell.a" is contained in at least one repeatable section. Please use JMESPath syntax to select one or more target sections.'],
+    ['no jmespath for repeating y', {y: {search_quantity: 'results.material.topology.cell.a'}}, 'The quantity "results.material.topology.cell.a" is contained in at least one repeatable section. Please use JMESPath syntax to select one or more target sections.'],
+    ['no jmespath for repeating color', {markers: {color: {search_quantity: 'results.material.topology.cell.a'}}}, 'The quantity "results.material.topology.cell.a" is contained in at least one repeatable section. Please use JMESPath syntax to select one or more target sections.'],
+    ['invalid x unit', {x: {search_quantity: 'results.material.topology[0].cell.a', unit: 'nounit'}}, 'Unit "nounit" not found.'],
+    ['invalid y unit', {y: {search_quantity: 'results.material.topology[0].cell.a', unit: 'nounit'}}, 'Unit "nounit" not found.'],
+    ['invalid color unit', {markers: {color: {search_quantity: 'results.material.topology[0].cell.a', unit: 'nounit'}}}, 'Unit "nounit" not found.'],
+    ['incompatible x unit', {x: {search_quantity: 'results.material.topology[0].cell.a', unit: 'joule'}}, 'Unit "joule" is incompatible with dimension "length".'],
+    ['incompatible y unit', {y: {search_quantity: 'results.material.topology[0].cell.a', unit: 'joule'}}, 'Unit "joule" is incompatible with dimension "length".'],
+    ['incompatible color unit', {markers: {color: {search_quantity: 'results.material.topology[0].cell.a', unit: 'joule'}}}, 'Unit "joule" is incompatible with dimension "length".']
   ])('%s', async (name, config, error) => {
     const finalConfig = {
       id: '0',
diff --git a/gui/src/components/search/widgets/WidgetTerms.js b/gui/src/components/search/widgets/WidgetTerms.js
index f368cc0bfd..130ec89542 100644
--- a/gui/src/components/search/widgets/WidgetTerms.js
+++ b/gui/src/components/search/widgets/WidgetTerms.js
@@ -102,15 +102,15 @@ export const WidgetTerms = React.memo((
   id,
   title,
   description,
-  quantity,
+  search_quantity,
   scale,
-  showinput,
+  show_input,
   className,
   'data-testid': testID
 }) => {
   const {useAgg, useFilterState, filterData} = useSearchContext()
   const styles = useStyles()
-  const [filter, setFilter] = useFilterState(quantity)
+  const [filter, setFilter] = useFilterState(search_quantity)
   const { height, ref } = useResizeDetector()
   const { useSetWidget } = useSearchContext()
   const setWidget = useSetWidget(id)
@@ -122,11 +122,11 @@ export const WidgetTerms = React.memo((
     // If a fixed list of options is used, we must restrict the aggregation
     // return values with 'include'. Otherwise the returned results may not
     // contain the correct values.
-    const options = filterData[quantity]?.options
+    const options = filterData[search_quantity]?.options
     if (options) config.include = Object.keys(options)
     return config
-  }, [aggSize, filterData, quantity])
-  const agg = useAgg(quantity, !isNil(height), id, aggConfig)
+  }, [aggSize, filterData, search_quantity])
+  const agg = useAgg(search_quantity, !isNil(height), id, aggConfig)
   const max = agg ? Math.max(...agg.data.map(option => option.nested_count)) : 0
 
   const handleChange = useCallback((event, key, selected) => {
@@ -188,7 +188,7 @@ export const WidgetTerms = React.memo((
 
   return <Widget
     id={id}
-    quantity={quantity}
+    quantity={search_quantity}
     title={title}
     description={description}
     onEdit={handleEdit}
@@ -205,10 +205,10 @@ export const WidgetTerms = React.memo((
     <InputTooltip>
       <div className={clsx(styles.outerContainer)}>
         <div className={clsx(styles.innerContainer)}>
-          {showinput
+          {show_input
             ? <InputTextQuantity
                 className={styles.textField}
-                quantity={quantity}
+                quantity={search_quantity}
                 disabled={false}
                 disableSuggestions={false}
                 fullWidth
@@ -238,11 +238,11 @@ WidgetTerms.propTypes = {
   id: PropTypes.string.isRequired,
   title: PropTypes.string,
   description: PropTypes.string,
-  quantity: PropTypes.string,
+  search_quantity: PropTypes.string,
   nbins: PropTypes.number,
   scale: PropTypes.string,
   autorange: PropTypes.bool,
-  showinput: PropTypes.bool,
+  show_input: PropTypes.bool,
   className: PropTypes.string,
   'data-testid': PropTypes.string
 }
@@ -307,12 +307,12 @@ export const WidgetTermsEdit = React.memo((props) => {
       <WidgetEditGroup title="x axis">
         <WidgetEditOption>
           <InputMetainfo
-            label="quantity"
-            value={settings.quantity}
-            error={errors.quantity}
-            onChange={(value) => handleChange('quantity', value)}
-            onSelect={(value) => handleAccept('quantity', value)}
-            onError={(value) => handleError('quantity', value)}
+            label="Search quantity"
+            value={settings.search_quantity}
+            error={errors.search_quantity}
+            onChange={(value) => handleChange('search_quantity', value)}
+            onSelect={(value) => handleAccept('search_quantity', value)}
+            onError={(value) => handleError('search_quantity', value)}
             dtypes={dtypes}
             dtypesRepeatable={dtypes}
             disableNonAggregatable
@@ -336,7 +336,7 @@ export const WidgetTermsEdit = React.memo((props) => {
       <WidgetEditGroup title="general">
         <WidgetEditOption>
           <InputTextField
-            label="title"
+            label="Title"
             fullWidth
             value={settings?.title}
             onChange={(event) => handleChange('title', event.target.value)}
@@ -344,7 +344,7 @@ export const WidgetTermsEdit = React.memo((props) => {
         </WidgetEditOption>
         <WidgetEditOption>
           <FormControlLabel
-            control={<Checkbox checked={settings.showinput} onChange={(event, value) => handleChange('showinput', value)}/>}
+            control={<Checkbox checked={settings.show_input} onChange={(event, value) => handleChange('show_input', value)}/>}
             label='Show input field'
           />
         </WidgetEditOption>
@@ -356,16 +356,16 @@ WidgetTermsEdit.propTypes = {
   id: PropTypes.string.isRequired,
   editing: PropTypes.bool,
   visible: PropTypes.bool,
-  quantity: PropTypes.string,
+  search_quantity: PropTypes.string,
   scale: PropTypes.string,
   nbins: PropTypes.number,
   autorange: PropTypes.bool,
-  showinput: PropTypes.bool,
+  show_input: PropTypes.bool,
   onClose: PropTypes.func
 }
 
 export const schemaWidgetTerms = schemaWidget.shape({
-  quantity: string().required('Quantity is required.'),
+  search_quantity: string().required('Search quantity is required.'),
   scale: string().required('Scale is required.'),
-  showinput: bool()
+  show_input: bool()
 })
diff --git a/gui/src/components/search/widgets/WidgetTerms.spec.js b/gui/src/components/search/widgets/WidgetTerms.spec.js
index e6548c80b2..33880708fd 100644
--- a/gui/src/components/search/widgets/WidgetTerms.spec.js
+++ b/gui/src/components/search/widgets/WidgetTerms.spec.js
@@ -58,11 +58,11 @@ describe('initial state is loaded correctly', () => {
       [],
       undefined
     ]
-  ])('%s', async (name, quantity, items, prompt) => {
+  ])('%s', async (name, search_quantity, items, prompt) => {
     const widget = {
       id: '0',
       scale: 'linear',
-      quantity: quantity
+      search_quantity: search_quantity
     }
     renderSearchEntry(<WidgetTerms {...widget} />)
     await expectWidgetTerms(widget, false, items, prompt)
diff --git a/gui/src/components/uploads/SectionSelectDialog.js b/gui/src/components/uploads/SectionSelectDialog.js
index dad05e574a..9187165cd6 100644
--- a/gui/src/components/uploads/SectionSelectDialog.js
+++ b/gui/src/components/uploads/SectionSelectDialog.js
@@ -30,7 +30,7 @@ import {useApi} from '../api'
 import {useUploadPageContext} from './UploadPageContext'
 import {useEntryStore} from '../entry/EntryContext'
 import {traverse, useGlobalMetainfo} from '../archive/metainfo'
-import { defaultFilterGroups, quantityNameSearch } from '../search/FilterRegistry'
+import { quantityNameSearch } from '../search/FilterRegistry'
 import { SearchResults } from '../search/SearchResults'
 import {useDataStore} from '../DataStore'
 import {pluralize, resolveNomadUrlNoThrow} from "../../utils"
@@ -44,12 +44,6 @@ const searchDialogContext = React.createContext()
 const context = cloneDeep(ui?.apps?.options?.entries)
 context.search_syntaxes.exclude = undefined
 
-const allFilters = new Set(defaultFilterGroups && (Object.keys(context?.filter_menus?.options))
-  .map(filter => {
-    const group = defaultFilterGroups?.[filter]
-    return group ? Array.from(group) : []
-  }).flat())
-
 const useStyles = makeStyles(theme => ({
   dialog: {
     width: '100%',
@@ -218,20 +212,19 @@ function SearchBox({open, onCancel, onSelectedChanged, selected}) {
   const {
     useSetFilter,
     useFilters,
-    useFiltersLocked,
+    filters: filterNames,
     useUpdateFilter,
     filters: filterList
   } = useSearchContext()
-  const filtersLocked = useFiltersLocked()
-  const filters = useFilters([...allFilters]
+  const filters = useFilters([...filterNames]
     .filter(
       filter => filter !== 'visibility' &&
       filter !== 'processed' &&
       filter !== 'upload_id' &&
       filter !== 'published' &&
-      filter !== 'main_author.user_id' &&
-      !filtersLocked[filter]
-    ))
+      filter !== 'main_author.user_id'
+    )
+  )
   const updateFilter = useUpdateFilter()
   const uploadContext = useUploadPageContext()
   const entryContext = useEntryStore()
@@ -416,7 +409,7 @@ function SectionSelectDialog(props) {
     initialPagination={context?.pagination}
     initialColumns={columns}
     initialRows={rows}
-    initialFilterMenus={context?.filter_menus}
+    initialMenu={context?.menu}
     initialFiltersLocked={filtersLocked}
     initialSearchSyntaxes={context?.search_syntaxes}
     id='sectionselect'
diff --git a/gui/src/components/uploads/UploadSearchMenu.js b/gui/src/components/uploads/UploadSearchMenu.js
index dc03f86aa2..bebc3591e2 100644
--- a/gui/src/components/uploads/UploadSearchMenu.js
+++ b/gui/src/components/uploads/UploadSearchMenu.js
@@ -31,7 +31,10 @@ const UploadSearchMenu = React.memo(({
   }
   const menu = filteredMenus[0]
     return (
-      <MenuBarRoute menu={menu} label={'Search in this upload'} initialFilters={{upload_id: uploadId}}>
+      <MenuBarRoute
+        menu={menu}
+        label={'Search in this upload'}
+        initialFilters={{upload_id: uploadId}}>
         <SearchIcon/>
       </MenuBarRoute>
     )
diff --git a/gui/src/utils.js b/gui/src/utils.js
index 1346991388..ca5004af38 100644
--- a/gui/src/utils.js
+++ b/gui/src/utils.js
@@ -245,6 +245,15 @@ export function titleCase(str) {
   return splitStr.join(' ')
 }
 
+/**
+ * Converts snake case variable names to camel case.
+ * @param {*} str Variable name in snake_case
+ * @returns Variable name in camelCase
+ */
+export function camelCase(str) {
+  return str.toLowerCase().replace(/[-_][a-z]/g, (group) => group.slice(-1).toUpperCase())
+}
+
 export function nameList(users, expanded) {
   const names = users.map(user => titleCase(user.name)).filter(name => name !== '')
   if (names.length > 3 && !expanded) {
@@ -839,19 +848,6 @@ export function pluralize(word, count, inclusive, format = true, prefix) {
     : `${prefix} `}${form}`
 }
 
-/**
- * Used to create a formatted label for a metainfo name or value. Replaces
- * underscores with whitespace and capitalizes the first letters.
- *
- * @param {str} name Metainfo name
- * @returns A formatted label constructed from the metainfo name.
- */
-export function formatLabel(label) {
-  label = label.replace(/_/g, ' ')
-  label = startCase(label)
-  return label
-}
-
 /**
  * Used for testing purposes: setting a data-testid to this value signals that the
  * component waits for further updates of some kind. This is used by some automated tests
diff --git a/gui/tests/artifacts.js b/gui/tests/artifacts.js
index 43db8aed4f..d2e1e09d96 100644
--- a/gui/tests/artifacts.js
+++ b/gui/tests/artifacts.js
@@ -3601,10 +3601,10 @@ window.nomadArtifacts = {
       "type": {
         "type_kind": "enum",
         "type_data": [
-          "",
           "MaxEnt",
           "Pade",
-          "SVD"
+          "SVD",
+          "Stochastic"
         ]
       },
       "shape": [],
@@ -36087,10 +36087,10 @@ window.nomadArtifacts = {
                 "type": {
                   "type_kind": "enum",
                   "type_data": [
-                    "",
                     "MaxEnt",
                     "Pade",
-                    "SVD"
+                    "SVD",
+                    "Stochastic"
                   ]
                 },
                 "shape": []
diff --git a/gui/tests/env.js b/gui/tests/env.js
index 26e05f1a58..33faca4662 100644
--- a/gui/tests/env.js
+++ b/gui/tests/env.js
@@ -610,129 +610,1770 @@ window.nomadEnv = {
               "enabled": true
             }
           },
-          "filter_menus": {
-            "options": {
-              "material": {
-                "label": "Material",
-                "level": 0,
-                "size": "s"
+          "menu": {
+            "width": 12,
+            "show_header": true,
+            "title": "Filters",
+            "type": "menu",
+            "size": "sm",
+            "indentation": 0,
+            "items": [
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Material",
+                "type": "menu",
+                "size": "md"
               },
-              "elements": {
-                "label": "Elements / Formula",
-                "level": 1,
-                "size": "xl"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Elements / Formula",
+                "type": "menu",
+                "size": "xxl",
+                "indentation": 1,
+                "items": [
+                  {
+                    "type": "periodic_table",
+                    "search_quantity": "results.material.elements",
+                    "scale": "linear",
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.chemical_formula_hill",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 6,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.chemical_formula_iupac",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 6,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.chemical_formula_reduced",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 6,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.chemical_formula_anonymous",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 6,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.material.n_elements",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "structure": {
-                "label": "Structure / Symmetry",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Structure / Symmetry",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "results.material.structural_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.symmetry.bravais_lattice",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 2,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.symmetry.crystal_system",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 2,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.symmetry.space_group_symbol",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.symmetry.structure_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 5,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.symmetry.strukturbericht_designation",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.symmetry.point_group",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.symmetry.hall_symbol",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.symmetry.prototype_aflow_id",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "method": {
-                "label": "Method",
-                "level": 0,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Method",
+                "type": "menu",
+                "size": "md",
+                "items": [
+                  {
+                    "search_quantity": "results.method.simulation.program_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.program_version",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "precision": {
-                "label": "Precision",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Precision",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.method.simulation.precision.k_line_density",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.precision.native_tier",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.precision.basis_set",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 5,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.method.simulation.precision.planewave_cutoff",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.method.simulation.precision.apw_cutoff",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "dft": {
-                "label": "DFT",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "DFT",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "results.method.method_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": false,
+                    "options": {
+                      "DFT": {
+                        "label": "Search DFT entries"
+                      }
+                    },
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": false
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.dft.xc_functional_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.dft.xc_functional_names",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.method.simulation.dft.exact_exchange_mixing_factor",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.method.simulation.dft.hubbard_kanamori_model.u_effective",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.dft.core_electron_treatment",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.dft.relativity_method",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "tb": {
-                "label": "TB",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "TB",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "results.method.method_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": false,
+                    "options": {
+                      "TB": {
+                        "label": "Search TB entries"
+                      }
+                    },
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": false
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.tb.type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.tb.localization_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "gw": {
-                "label": "GW",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "GW",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "results.method.method_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": false,
+                    "options": {
+                      "GW": {
+                        "label": "Search GW entries"
+                      }
+                    },
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": false
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.gw.type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.gw.starting_point_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.gw.basis_set_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "bse": {
-                "label": "BSE",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "BSE",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "results.method.method_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": false,
+                    "options": {
+                      "BSE": {
+                        "label": "Search BSE entries"
+                      }
+                    },
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": false
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.bse.type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.bse.solver",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.bse.starting_point_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.bse.starting_point_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.bse.basis_set_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.bse.gw_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "dmft": {
-                "label": "DMFT",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "DMFT",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "results.method.method_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": false,
+                    "options": {
+                      "DMFT": {
+                        "label": "Search DMFT entries"
+                      }
+                    },
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": false
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.dmft.impurity_solver_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 2,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.method.simulation.dmft.inverse_temperature",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.dmft.magnetic_state",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.method.simulation.dmft.u",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.method.simulation.dmft.jh",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.dmft.analytical_continuation",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "eels": {
-                "label": "EELS",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "EELS",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "results.method.method_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": false,
+                    "options": {
+                      "EELS": {
+                        "label": "Search EELS entries"
+                      }
+                    },
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": false
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.spectroscopic.spectra.provenance.eels",
+                    "items": [
+                      {
+                        "search_quantity": "results.properties.spectroscopic.spectra.provenance.eels.detector_type",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": true,
+                        "width": 12,
+                        "show_header": true,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.spectroscopic.spectra.provenance.eels.resolution",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.spectroscopic.spectra.provenance.eels.min_energy",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.spectroscopic.spectra.provenance.eels.max_energy",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  }
+                ]
               },
-              "workflow": {
-                "label": "Workflow",
-                "level": 0,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Workflow",
+                "type": "menu",
+                "size": "md"
               },
-              "molecular_dynamics": {
-                "label": "Molecular dynamics",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Molecular dynamics",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.thermodynamic.trajectory",
+                    "items": [
+                      {
+                        "search_quantity": "results.properties.thermodynamic.trajectory.available_properties",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": false,
+                        "width": 12,
+                        "show_header": true,
+                        "options": 4,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "search_quantity": "results.properties.thermodynamic.trajectory.provenance.molecular_dynamics.ensemble_type",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": false,
+                        "width": 12,
+                        "show_header": true,
+                        "options": 2,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.thermodynamic.trajectory.provenance.molecular_dynamics.time_step",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  }
+                ]
               },
-              "geometry_optimization": {
-                "label": "Geometry Optimization",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Geometry Optimization",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "results.properties.available_properties",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": false,
+                    "options": {
+                      "geometry_optimization": {
+                        "label": "Search geometry optimization entries"
+                      }
+                    },
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": false
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.geometry_optimization",
+                    "items": [
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.geometry_optimization.final_energy_difference",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.geometry_optimization.final_force_maximum",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.geometry_optimization.final_displacement_maximum",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  }
+                ]
               },
-              "properties": {
-                "label": "Properties",
-                "level": 0,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Properties",
+                "type": "menu",
+                "size": "md"
               },
-              "electronic": {
-                "label": "Electronic",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Electronic",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "electronic_properties",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.electronic.band_structure_electronic.band_gap",
+                    "items": [
+                      {
+                        "search_quantity": "results.properties.electronic.band_structure_electronic.band_gap.type",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": false,
+                        "width": 12,
+                        "show_header": true,
+                        "options": 2,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.electronic.band_structure_electronic.band_gap.value",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.electronic.band_structure_electronic",
+                    "items": [
+                      {
+                        "search_quantity": "results.properties.electronic.band_structure_electronic.spin_polarized",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": false,
+                        "width": 12,
+                        "show_header": true,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.electronic.dos_electronic",
+                    "items": [
+                      {
+                        "search_quantity": "results.properties.electronic.dos_electronic.spin_polarized",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": false,
+                        "width": 12,
+                        "show_header": true,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  }
+                ]
               },
-              "vibrational": {
-                "label": "Vibrational",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Vibrational",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "vibrational_properties",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "mechanical": {
-                "label": "Mechanical",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Mechanical",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "mechanical_properties",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.mechanical.bulk_modulus",
+                    "items": [
+                      {
+                        "search_quantity": "results.properties.mechanical.bulk_modulus.type",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": true,
+                        "width": 12,
+                        "show_header": true,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.mechanical.bulk_modulus.value",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.mechanical.shear_modulus",
+                    "items": [
+                      {
+                        "search_quantity": "results.properties.mechanical.shear_modulus.type",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": false,
+                        "width": 12,
+                        "show_header": true,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.mechanical.shear_modulus.value",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.mechanical.energy_volume_curve",
+                    "items": [
+                      {
+                        "search_quantity": "results.properties.mechanical.energy_volume_curve.type",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": true,
+                        "width": 12,
+                        "show_header": true,
+                        "options": 5,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  }
+                ]
               },
-              "usecases": {
-                "label": "Use Cases",
-                "level": 0,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Use Cases",
+                "type": "menu",
+                "size": "md"
               },
-              "solarcell": {
-                "label": "Solar Cells",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Solar Cells",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.properties.optoelectronic.solar_cell.efficiency",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.properties.optoelectronic.solar_cell.fill_factor",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.properties.optoelectronic.solar_cell.open_circuit_voltage",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.properties.optoelectronic.solar_cell.short_circuit_current_density",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.properties.optoelectronic.solar_cell.illumination_intensity",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.properties.optoelectronic.solar_cell.device_area",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.properties.optoelectronic.solar_cell.device_architecture",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.properties.optoelectronic.solar_cell.device_stack",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.properties.optoelectronic.solar_cell.absorber",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.properties.optoelectronic.solar_cell.absorber_fabrication",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.properties.optoelectronic.solar_cell.electron_transport_layer",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.properties.optoelectronic.solar_cell.hole_transport_layer",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.properties.optoelectronic.solar_cell.substrate",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.properties.optoelectronic.solar_cell.back_contact",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "heterogeneouscatalyst": {
-                "label": "Heterogeneous Catalysis",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Heterogeneous Catalysis",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "results.properties.catalytic.reaction.name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.catalytic.reaction.reactants",
+                    "items": [
+                      {
+                        "search_quantity": "results.properties.catalytic.reaction.reactants.name",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": true,
+                        "width": 12,
+                        "show_header": true,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.catalytic.reaction.reactants.conversion",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.catalytic.reaction.reactants.gas_concentration_in",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.catalytic.reaction.reactants.gas_concentration_out",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.catalytic.reaction.products",
+                    "items": [
+                      {
+                        "search_quantity": "results.properties.catalytic.reaction.products.name",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": true,
+                        "width": 12,
+                        "show_header": true,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.catalytic.reaction.products.selectivity",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.catalytic.reaction.products.gas_concentration_out",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.properties.catalytic.reaction.reaction_conditions.temperature",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.catalytic.catalyst",
+                    "items": [
+                      {
+                        "search_quantity": "results.properties.catalytic.catalyst.catalyst_type",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": true,
+                        "width": 12,
+                        "show_header": true,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "search_quantity": "results.properties.catalytic.catalyst.preparation_method",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": true,
+                        "width": 12,
+                        "show_header": true,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "search_quantity": "results.properties.catalytic.catalyst.catalyst_name",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": true,
+                        "width": 12,
+                        "show_header": true,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "search_quantity": "results.properties.catalytic.catalyst.characterization_methods",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": true,
+                        "width": 12,
+                        "show_header": true,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.catalytic.catalyst.surface_area",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  }
+                ]
               },
-              "author": {
-                "label": "Author / Origin / Dataset",
-                "level": 0,
-                "size": "m"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Author / Origin / Dataset",
+                "type": "menu",
+                "size": "lg",
+                "items": [
+                  {
+                    "search_quantity": "authors.name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "upload_create_time",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "external_db",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 5,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "datasets.dataset_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "datasets.doi",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "metadata": {
-                "label": "Visibility / IDs / Schema",
-                "level": 0,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Visibility / IDs / Schema",
+                "type": "menu",
+                "size": "md",
+                "items": [
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "visibility"
+                  },
+                  {
+                    "search_quantity": "entry_id",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "upload_id",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "upload_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.material_id",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "datasets.dataset_id",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "definitions"
+                  }
+                ]
               },
-              "optimade": {
-                "label": "Optimade",
-                "level": 0,
-                "size": "m"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Optimade",
+                "type": "menu",
+                "size": "lg",
+                "items": [
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "optimade"
+                  }
+                ]
               }
-            }
+            ]
           },
           "filters": {
             "exclude": [
@@ -741,6 +2382,13 @@ window.nomadEnv = {
               "combine"
             ]
           },
+          "search_quantities": {
+            "exclude": [
+              "mainfile",
+              "entry_name",
+              "combine"
+            ]
+          },
           "search_syntaxes": {
             "exclude": [
               "free_text"
@@ -885,109 +2533,1269 @@ window.nomadEnv = {
               "enabled": true
             }
           },
-          "filter_menus": {
-            "options": {
-              "material": {
-                "label": "Material",
-                "level": 0,
-                "size": "s"
+          "menu": {
+            "width": 12,
+            "show_header": true,
+            "title": "Filters",
+            "type": "menu",
+            "size": "sm",
+            "indentation": 0,
+            "items": [
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Material",
+                "type": "menu",
+                "size": "md"
               },
-              "elements": {
-                "label": "Elements / Formula",
-                "level": 1,
-                "size": "xl"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Elements / Formula",
+                "type": "menu",
+                "size": "xxl",
+                "indentation": 1,
+                "items": [
+                  {
+                    "type": "periodic_table",
+                    "search_quantity": "results.material.elements",
+                    "scale": "linear",
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.chemical_formula_hill",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 6,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.chemical_formula_iupac",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 6,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.chemical_formula_reduced",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 6,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.chemical_formula_anonymous",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 6,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.material.n_elements",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "structure": {
-                "label": "Structure / Symmetry",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Structure / Symmetry",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "results.material.structural_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.symmetry.bravais_lattice",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 2,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.symmetry.crystal_system",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 2,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.symmetry.space_group_symbol",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.symmetry.structure_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 5,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.symmetry.strukturbericht_designation",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.symmetry.point_group",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.symmetry.hall_symbol",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.symmetry.prototype_aflow_id",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "method": {
-                "label": "Method",
-                "level": 0,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Method",
+                "type": "menu",
+                "size": "md",
+                "items": [
+                  {
+                    "search_quantity": "results.method.simulation.program_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.program_version",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "precision": {
-                "label": "Precision",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Precision",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.method.simulation.precision.k_line_density",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.precision.native_tier",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.precision.basis_set",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 5,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.method.simulation.precision.planewave_cutoff",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.method.simulation.precision.apw_cutoff",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "dft": {
-                "label": "DFT",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "DFT",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "results.method.method_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": false,
+                    "options": {
+                      "DFT": {
+                        "label": "Search DFT entries"
+                      }
+                    },
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": false
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.dft.xc_functional_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.dft.xc_functional_names",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.method.simulation.dft.exact_exchange_mixing_factor",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.method.simulation.dft.hubbard_kanamori_model.u_effective",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.dft.core_electron_treatment",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.dft.relativity_method",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "tb": {
-                "label": "TB",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "TB",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "results.method.method_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": false,
+                    "options": {
+                      "TB": {
+                        "label": "Search TB entries"
+                      }
+                    },
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": false
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.tb.type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.tb.localization_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "gw": {
-                "label": "GW",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "GW",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "results.method.method_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": false,
+                    "options": {
+                      "GW": {
+                        "label": "Search GW entries"
+                      }
+                    },
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": false
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.gw.type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.gw.starting_point_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.gw.basis_set_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "bse": {
-                "label": "BSE",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "BSE",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "results.method.method_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": false,
+                    "options": {
+                      "BSE": {
+                        "label": "Search BSE entries"
+                      }
+                    },
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": false
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.bse.type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.bse.solver",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.bse.starting_point_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.bse.starting_point_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.bse.basis_set_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.bse.gw_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "dmft": {
-                "label": "DMFT",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "DMFT",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "results.method.method_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": false,
+                    "options": {
+                      "DMFT": {
+                        "label": "Search DMFT entries"
+                      }
+                    },
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": false
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.dmft.impurity_solver_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 2,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.method.simulation.dmft.inverse_temperature",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.dmft.magnetic_state",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.method.simulation.dmft.u",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.method.simulation.dmft.jh",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.dmft.analytical_continuation",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "workflow": {
-                "label": "Workflow",
-                "level": 0,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Workflow",
+                "type": "menu",
+                "size": "md"
               },
-              "molecular_dynamics": {
-                "label": "Molecular dynamics",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Molecular dynamics",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.thermodynamic.trajectory",
+                    "items": [
+                      {
+                        "search_quantity": "results.properties.thermodynamic.trajectory.available_properties",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": false,
+                        "width": 12,
+                        "show_header": true,
+                        "options": 4,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "search_quantity": "results.properties.thermodynamic.trajectory.provenance.molecular_dynamics.ensemble_type",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": false,
+                        "width": 12,
+                        "show_header": true,
+                        "options": 2,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.thermodynamic.trajectory.provenance.molecular_dynamics.time_step",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  }
+                ]
               },
-              "geometry_optimization": {
-                "label": "Geometry Optimization",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Geometry Optimization",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "results.properties.available_properties",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": false,
+                    "options": {
+                      "geometry_optimization": {
+                        "label": "Search geometry optimization entries"
+                      }
+                    },
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": false
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.geometry_optimization",
+                    "items": [
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.geometry_optimization.final_energy_difference",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.geometry_optimization.final_force_maximum",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.geometry_optimization.final_displacement_maximum",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  }
+                ]
               },
-              "properties": {
-                "label": "Properties",
-                "level": 0,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Properties",
+                "type": "menu",
+                "size": "md"
               },
-              "electronic": {
-                "label": "Electronic",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Electronic",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "electronic_properties",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.electronic.band_structure_electronic.band_gap",
+                    "items": [
+                      {
+                        "search_quantity": "results.properties.electronic.band_structure_electronic.band_gap.type",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": false,
+                        "width": 12,
+                        "show_header": true,
+                        "options": 2,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.electronic.band_structure_electronic.band_gap.value",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.electronic.band_structure_electronic",
+                    "items": [
+                      {
+                        "search_quantity": "results.properties.electronic.band_structure_electronic.spin_polarized",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": false,
+                        "width": 12,
+                        "show_header": true,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.electronic.dos_electronic",
+                    "items": [
+                      {
+                        "search_quantity": "results.properties.electronic.dos_electronic.spin_polarized",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": false,
+                        "width": 12,
+                        "show_header": true,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  }
+                ]
               },
-              "vibrational": {
-                "label": "Vibrational",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Vibrational",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "vibrational_properties",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "mechanical": {
-                "label": "Mechanical",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Mechanical",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "mechanical_properties",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.mechanical.bulk_modulus",
+                    "items": [
+                      {
+                        "search_quantity": "results.properties.mechanical.bulk_modulus.type",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": true,
+                        "width": 12,
+                        "show_header": true,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.mechanical.bulk_modulus.value",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.mechanical.shear_modulus",
+                    "items": [
+                      {
+                        "search_quantity": "results.properties.mechanical.shear_modulus.type",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": false,
+                        "width": 12,
+                        "show_header": true,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.mechanical.shear_modulus.value",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.mechanical.energy_volume_curve",
+                    "items": [
+                      {
+                        "search_quantity": "results.properties.mechanical.energy_volume_curve.type",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": true,
+                        "width": 12,
+                        "show_header": true,
+                        "options": 5,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  }
+                ]
               },
-              "author": {
-                "label": "Author / Origin / Dataset",
-                "level": 0,
-                "size": "m"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Author / Origin / Dataset",
+                "type": "menu",
+                "size": "lg",
+                "items": [
+                  {
+                    "search_quantity": "authors.name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "upload_create_time",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "external_db",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 5,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "datasets.dataset_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "datasets.doi",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "metadata": {
-                "label": "Visibility / IDs / Schema",
-                "level": 0,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Visibility / IDs / Schema",
+                "type": "menu",
+                "size": "md",
+                "items": [
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "visibility"
+                  },
+                  {
+                    "search_quantity": "entry_id",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "upload_id",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "upload_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.material_id",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "datasets.dataset_id",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "definitions"
+                  }
+                ]
               },
-              "optimade": {
-                "label": "Optimade",
-                "level": 0,
-                "size": "m"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Optimade",
+                "type": "menu",
+                "size": "lg",
+                "items": [
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "optimade"
+                  }
+                ]
               }
-            }
+            ]
           },
           "filters": {
             "exclude": [
@@ -996,10 +3804,19 @@ window.nomadEnv = {
               "combine"
             ]
           },
+          "search_quantities": {
+            "exclude": [
+              "mainfile",
+              "entry_name",
+              "combine"
+            ]
+          },
           "dashboard": {
             "widgets": [
               {
                 "type": "periodictable",
+                "search_quantity": "results.material.elements",
+                "scale": "linear",
                 "layout": {
                   "lg": {
                     "h": 11,
@@ -1041,12 +3858,13 @@ window.nomadEnv = {
                     "minH": 3,
                     "minW": 3
                   }
-                },
-                "quantity": "results.material.elements",
-                "scale": "linear"
+                }
               },
               {
+                "search_quantity": "results.material.symmetry.space_group_symbol",
                 "type": "terms",
+                "scale": "linear",
+                "show_input": true,
                 "layout": {
                   "lg": {
                     "h": 5,
@@ -1088,13 +3906,13 @@ window.nomadEnv = {
                     "minH": 3,
                     "minW": 3
                   }
-                },
-                "quantity": "results.material.symmetry.space_group_symbol",
-                "scale": "linear",
-                "showinput": true
+                }
               },
               {
+                "search_quantity": "results.material.structural_type",
                 "type": "terms",
+                "scale": "log",
+                "show_input": false,
                 "layout": {
                   "lg": {
                     "h": 6,
@@ -1136,13 +3954,13 @@ window.nomadEnv = {
                     "minH": 3,
                     "minW": 3
                   }
-                },
-                "quantity": "results.material.structural_type",
-                "scale": "log",
-                "showinput": false
+                }
               },
               {
+                "search_quantity": "results.method.simulation.program_name",
                 "type": "terms",
+                "scale": "log",
+                "show_input": true,
                 "layout": {
                   "lg": {
                     "h": 6,
@@ -1184,13 +4002,13 @@ window.nomadEnv = {
                     "minH": 3,
                     "minW": 3
                   }
-                },
-                "quantity": "results.method.simulation.program_name",
-                "scale": "log",
-                "showinput": true
+                }
               },
               {
+                "search_quantity": "results.material.symmetry.crystal_system",
                 "type": "terms",
+                "scale": "linear",
+                "show_input": false,
                 "layout": {
                   "lg": {
                     "h": 5,
@@ -1232,10 +4050,7 @@ window.nomadEnv = {
                     "minH": 3,
                     "minW": 3
                   }
-                },
-                "quantity": "results.material.symmetry.crystal_system",
-                "scale": "linear",
-                "showinput": false
+                }
               }
             ]
           },
@@ -1310,117 +4125,1207 @@ window.nomadEnv = {
               "enabled": false
             }
           },
-          "filter_menus": {
-            "options": {
-              "material": {
-                "label": "Material",
-                "level": 0,
-                "size": "s"
+          "menu": {
+            "width": 12,
+            "show_header": true,
+            "title": "Filters",
+            "type": "menu",
+            "size": "sm",
+            "indentation": 0,
+            "items": [
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Material",
+                "type": "menu",
+                "size": "md"
               },
-              "elements": {
-                "label": "Elements / Formula",
-                "level": 1,
-                "size": "xl"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Elements / Formula",
+                "type": "menu",
+                "size": "xxl",
+                "indentation": 1,
+                "items": [
+                  {
+                    "type": "periodic_table",
+                    "search_quantity": "results.material.elements",
+                    "scale": "linear",
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.chemical_formula_hill",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 6,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.chemical_formula_iupac",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 6,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.chemical_formula_reduced",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 6,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.chemical_formula_anonymous",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 6,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.material.n_elements",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "structure": {
-                "label": "Structure / Symmetry",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Structure / Symmetry",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "results.material.structural_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.symmetry.bravais_lattice",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 2,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.symmetry.crystal_system",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 2,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.symmetry.space_group_symbol",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.symmetry.structure_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 5,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.symmetry.strukturbericht_designation",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.symmetry.point_group",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.symmetry.hall_symbol",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.symmetry.prototype_aflow_id",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "method": {
-                "label": "Method",
-                "level": 0,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Method",
+                "type": "menu",
+                "size": "md",
+                "items": [
+                  {
+                    "search_quantity": "results.method.simulation.program_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.program_version",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "dft": {
-                "label": "DFT",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "DFT",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "results.method.method_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": false,
+                    "options": {
+                      "DFT": {
+                        "label": "Search DFT entries"
+                      }
+                    },
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": false
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.dft.xc_functional_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.dft.xc_functional_names",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.method.simulation.dft.exact_exchange_mixing_factor",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.method.simulation.dft.hubbard_kanamori_model.u_effective",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.dft.core_electron_treatment",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.dft.relativity_method",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "tb": {
-                "label": "TB",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "TB",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "results.method.method_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": false,
+                    "options": {
+                      "TB": {
+                        "label": "Search TB entries"
+                      }
+                    },
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": false
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.tb.type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.tb.localization_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "gw": {
-                "label": "GW",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "GW",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "results.method.method_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": false,
+                    "options": {
+                      "GW": {
+                        "label": "Search GW entries"
+                      }
+                    },
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": false
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.gw.type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.gw.starting_point_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.gw.basis_set_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "bse": {
-                "label": "BSE",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "BSE",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "results.method.method_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": false,
+                    "options": {
+                      "BSE": {
+                        "label": "Search BSE entries"
+                      }
+                    },
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": false
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.bse.type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.bse.solver",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.bse.starting_point_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.bse.starting_point_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.bse.basis_set_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.bse.gw_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "dmft": {
-                "label": "DMFT",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "DMFT",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "results.method.method_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": false,
+                    "options": {
+                      "DMFT": {
+                        "label": "Search DMFT entries"
+                      }
+                    },
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": false
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.dmft.impurity_solver_type",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 2,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.method.simulation.dmft.inverse_temperature",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.dmft.magnetic_state",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.method.simulation.dmft.u",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.method.simulation.dmft.jh",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.dmft.analytical_continuation",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "workflow": {
-                "label": "Workflow",
-                "level": 0,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Workflow",
+                "type": "menu",
+                "size": "md"
               },
-              "molecular_dynamics": {
-                "label": "Molecular dynamics",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Molecular dynamics",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.thermodynamic.trajectory",
+                    "items": [
+                      {
+                        "search_quantity": "results.properties.thermodynamic.trajectory.available_properties",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": false,
+                        "width": 12,
+                        "show_header": true,
+                        "options": 4,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "search_quantity": "results.properties.thermodynamic.trajectory.provenance.molecular_dynamics.ensemble_type",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": false,
+                        "width": 12,
+                        "show_header": true,
+                        "options": 2,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.thermodynamic.trajectory.provenance.molecular_dynamics.time_step",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  }
+                ]
               },
-              "geometry_optimization": {
-                "label": "Geometry Optimization",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Geometry Optimization",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "results.properties.available_properties",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": false,
+                    "options": {
+                      "geometry_optimization": {
+                        "label": "Search geometry optimization entries"
+                      }
+                    },
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": false
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.geometry_optimization",
+                    "items": [
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.geometry_optimization.final_energy_difference",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.geometry_optimization.final_force_maximum",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.geometry_optimization.final_displacement_maximum",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  }
+                ]
               },
-              "properties": {
-                "label": "Properties",
-                "level": 0,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Properties",
+                "type": "menu",
+                "size": "md"
               },
-              "electronic": {
-                "label": "Electronic",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Electronic",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "electronic_properties",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.electronic.band_structure_electronic.band_gap",
+                    "items": [
+                      {
+                        "search_quantity": "results.properties.electronic.band_structure_electronic.band_gap.type",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": false,
+                        "width": 12,
+                        "show_header": true,
+                        "options": 2,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.electronic.band_structure_electronic.band_gap.value",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.electronic.band_structure_electronic",
+                    "items": [
+                      {
+                        "search_quantity": "results.properties.electronic.band_structure_electronic.spin_polarized",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": false,
+                        "width": 12,
+                        "show_header": true,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.electronic.dos_electronic",
+                    "items": [
+                      {
+                        "search_quantity": "results.properties.electronic.dos_electronic.spin_polarized",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": false,
+                        "width": 12,
+                        "show_header": true,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  }
+                ]
               },
-              "vibrational": {
-                "label": "Vibrational",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Vibrational",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "vibrational_properties",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "mechanical": {
-                "label": "Mechanical",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Mechanical",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "mechanical_properties",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.mechanical.bulk_modulus",
+                    "items": [
+                      {
+                        "search_quantity": "results.properties.mechanical.bulk_modulus.type",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": true,
+                        "width": 12,
+                        "show_header": true,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.mechanical.bulk_modulus.value",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.mechanical.shear_modulus",
+                    "items": [
+                      {
+                        "search_quantity": "results.properties.mechanical.shear_modulus.type",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": false,
+                        "width": 12,
+                        "show_header": true,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.mechanical.shear_modulus.value",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.mechanical.energy_volume_curve",
+                    "items": [
+                      {
+                        "search_quantity": "results.properties.mechanical.energy_volume_curve.type",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": true,
+                        "width": 12,
+                        "show_header": true,
+                        "options": 5,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  }
+                ]
               },
-              "author": {
-                "label": "Author / Origin / Dataset",
-                "level": 0,
-                "size": "m"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Author / Origin / Dataset",
+                "type": "menu",
+                "size": "lg",
+                "items": [
+                  {
+                    "search_quantity": "authors.name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "upload_create_time",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "external_db",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 5,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "datasets.dataset_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "datasets.doi",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "metadata": {
-                "label": "Visibility / IDs / Schema",
-                "level": 0,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Visibility / IDs / Schema",
+                "type": "menu",
+                "size": "md",
+                "items": [
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "visibility"
+                  },
+                  {
+                    "search_quantity": "entry_id",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "upload_id",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "upload_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.material_id",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "datasets.dataset_id",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "definitions"
+                  }
+                ]
               },
-              "optimade": {
-                "label": "Optimade",
-                "level": 0,
-                "size": "m"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Optimade",
+                "type": "menu",
+                "size": "lg",
+                "items": [
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "optimade"
+                  }
+                ]
               },
-              "combine": {
-                "level": 0,
-                "size": "s",
-                "actions": {
-                  "options": {
-                    "combine": {
-                      "type": "checkbox",
-                      "label": "Combine results from several entries",
-                      "quantity": "combine"
-                    }
+              {
+                "search_quantity": "combine",
+                "type": "terms",
+                "scale": "linear",
+                "show_input": false,
+                "width": 12,
+                "show_header": false,
+                "options": {
+                  "True": {
+                    "label": "Combine results from several entries",
+                    "description": "If selected, your filters may be matched from several entries that contain the same material. When unchecked, the material has to have a single entry that matches all your filters."
                   }
-                }
+                },
+                "n_columns": 1,
+                "sort_static": true,
+                "show_statistics": false
               }
-            }
+            ]
           },
           "filters": {
             "exclude": [
@@ -1428,6 +5333,12 @@ window.nomadEnv = {
               "entry_name"
             ]
           },
+          "search_quantities": {
+            "exclude": [
+              "mainfile",
+              "entry_name"
+            ]
+          },
           "search_syntaxes": {
             "exclude": [
               "free_text"
@@ -1547,44 +5458,370 @@ window.nomadEnv = {
               "enabled": true
             }
           },
-          "filter_menus": {
-            "options": {
-              "material": {
-                "label": "Material",
-                "level": 0,
-                "size": "s"
+          "menu": {
+            "width": 12,
+            "show_header": true,
+            "title": "Filters",
+            "type": "menu",
+            "size": "sm",
+            "indentation": 0,
+            "items": [
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Material",
+                "type": "menu",
+                "size": "md"
               },
-              "elements": {
-                "label": "Elements / Formula",
-                "level": 1,
-                "size": "xl"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Elements / Formula",
+                "type": "menu",
+                "size": "xxl",
+                "indentation": 1,
+                "items": [
+                  {
+                    "type": "periodic_table",
+                    "search_quantity": "results.material.elements",
+                    "scale": "linear",
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.chemical_formula_hill",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 6,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.chemical_formula_iupac",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 6,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.chemical_formula_reduced",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 6,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.chemical_formula_anonymous",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 6,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.material.n_elements",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "eln": {
-                "label": "Electronic Lab Notebook",
-                "level": 0,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Electronic Lab Notebook",
+                "type": "menu",
+                "size": "md",
+                "items": [
+                  {
+                    "search_quantity": "results.eln.sections",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.eln.tags",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.eln.methods",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.eln.instruments",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.eln.names",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.eln.descriptions",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.eln.lab_ids",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "custom_quantities": {
-                "label": "User Defined Quantities",
-                "level": 0,
-                "size": "l"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "User Defined Quantities",
+                "type": "menu",
+                "size": "xl",
+                "items": [
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "custom_quantities"
+                  }
+                ]
               },
-              "author": {
-                "label": "Author / Origin / Dataset",
-                "level": 0,
-                "size": "m"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Author / Origin / Dataset",
+                "type": "menu",
+                "size": "lg",
+                "items": [
+                  {
+                    "search_quantity": "authors.name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "upload_create_time",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "external_db",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 5,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "datasets.dataset_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "datasets.doi",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "metadata": {
-                "label": "Visibility / IDs / Schema",
-                "level": 0,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Visibility / IDs / Schema",
+                "type": "menu",
+                "size": "md",
+                "items": [
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "visibility"
+                  },
+                  {
+                    "search_quantity": "entry_id",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "upload_id",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "upload_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.material_id",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "datasets.dataset_id",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "definitions"
+                  }
+                ]
               },
-              "optimade": {
-                "label": "Optimade",
-                "level": 0,
-                "size": "m"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Optimade",
+                "type": "menu",
+                "size": "lg",
+                "items": [
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "optimade"
+                  }
+                ]
               }
-            }
+            ]
           },
           "filters": {
             "exclude": [
@@ -1593,6 +5830,13 @@ window.nomadEnv = {
               "combine"
             ]
           },
+          "search_quantities": {
+            "exclude": [
+              "mainfile",
+              "entry_name",
+              "combine"
+            ]
+          },
           "filters_locked": {
             "quantities": "data"
           }
@@ -1700,44 +5944,389 @@ window.nomadEnv = {
               "enabled": true
             }
           },
-          "filter_menus": {
-            "options": {
-              "material": {
-                "label": "Material",
-                "level": 0,
-                "size": "s"
+          "menu": {
+            "width": 12,
+            "show_header": true,
+            "title": "Filters",
+            "type": "menu",
+            "size": "sm",
+            "indentation": 0,
+            "items": [
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Material",
+                "type": "menu",
+                "size": "md"
               },
-              "elements": {
-                "label": "Elements / Formula",
-                "level": 1,
-                "size": "xl"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Elements / Formula",
+                "type": "menu",
+                "size": "xxl",
+                "indentation": 1,
+                "items": [
+                  {
+                    "type": "periodic_table",
+                    "search_quantity": "results.material.elements",
+                    "scale": "linear",
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.chemical_formula_hill",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 6,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.chemical_formula_iupac",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 6,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.chemical_formula_reduced",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 6,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.chemical_formula_anonymous",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 6,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "results.material.n_elements",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "method": {
-                "label": "Method",
-                "level": 0,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Method",
+                "type": "menu",
+                "size": "md",
+                "items": [
+                  {
+                    "search_quantity": "results.method.simulation.program_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.method.simulation.program_version",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "eels": {
-                "label": "EELS",
-                "level": 1,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "EELS",
+                "type": "menu",
+                "size": "md",
+                "indentation": 1,
+                "items": [
+                  {
+                    "search_quantity": "results.method.method_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": false,
+                    "options": {
+                      "EELS": {
+                        "label": "Search EELS entries"
+                      }
+                    },
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": false
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "nested_object",
+                    "path": "results.properties.spectroscopic.spectra.provenance.eels",
+                    "items": [
+                      {
+                        "search_quantity": "results.properties.spectroscopic.spectra.provenance.eels.detector_type",
+                        "type": "terms",
+                        "scale": "linear",
+                        "show_input": true,
+                        "width": 12,
+                        "show_header": true,
+                        "n_columns": 1,
+                        "sort_static": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.spectroscopic.spectra.provenance.eels.resolution",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.spectroscopic.spectra.provenance.eels.min_energy",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      },
+                      {
+                        "type": "histogram",
+                        "show_input": true,
+                        "x": {
+                          "search_quantity": "results.properties.spectroscopic.spectra.provenance.eels.max_energy",
+                          "scale": "linear"
+                        },
+                        "y": {
+                          "scale": "linear"
+                        },
+                        "autorange": false,
+                        "width": 12,
+                        "show_header": true,
+                        "show_statistics": true
+                      }
+                    ]
+                  }
+                ]
               },
-              "author": {
-                "label": "Author / Origin / Dataset",
-                "level": 0,
-                "size": "m"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Author / Origin / Dataset",
+                "type": "menu",
+                "size": "lg",
+                "items": [
+                  {
+                    "search_quantity": "authors.name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "type": "histogram",
+                    "show_input": true,
+                    "x": {
+                      "search_quantity": "upload_create_time",
+                      "scale": "linear"
+                    },
+                    "y": {
+                      "scale": "linear"
+                    },
+                    "autorange": false,
+                    "width": 12,
+                    "show_header": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "external_db",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": false,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 5,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "datasets.dataset_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "datasets.doi",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  }
+                ]
               },
-              "metadata": {
-                "label": "Visibility / IDs / Schema",
-                "level": 0,
-                "size": "s"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Visibility / IDs / Schema",
+                "type": "menu",
+                "size": "md",
+                "items": [
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "visibility"
+                  },
+                  {
+                    "search_quantity": "entry_id",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "upload_id",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "upload_name",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "results.material.material_id",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "search_quantity": "datasets.dataset_id",
+                    "type": "terms",
+                    "scale": "linear",
+                    "show_input": true,
+                    "width": 12,
+                    "show_header": true,
+                    "options": 0,
+                    "n_columns": 1,
+                    "sort_static": true,
+                    "show_statistics": true
+                  },
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "definitions"
+                  }
+                ]
               },
-              "optimade": {
-                "label": "Optimade",
-                "level": 0,
-                "size": "m"
+              {
+                "width": 12,
+                "show_header": true,
+                "title": "Optimade",
+                "type": "menu",
+                "size": "lg",
+                "items": [
+                  {
+                    "width": 12,
+                    "show_header": true,
+                    "type": "optimade"
+                  }
+                ]
               }
-            }
+            ]
           },
           "filters": {
             "exclude": [
@@ -1746,6 +6335,13 @@ window.nomadEnv = {
               "combine"
             ]
           },
+          "search_quantities": {
+            "exclude": [
+              "mainfile",
+              "entry_name",
+              "combine"
+            ]
+          },
           "filters_locked": {
             "results.method.method_name": "EELS"
           },
@@ -2938,34 +7534,200 @@ window.nomadEnv = {
                 "enabled": true
               }
             },
-            "filter_menus": {
-              "options": {
-                "custom_quantities": {
-                  "label": "Notebooks",
-                  "level": 0,
-                  "size": "l"
+            "menu": {
+              "width": 12,
+              "show_header": true,
+              "title": "Filters",
+              "type": "menu",
+              "size": "sm",
+              "indentation": 0,
+              "items": [
+                {
+                  "width": 12,
+                  "show_header": true,
+                  "title": "Notebooks",
+                  "type": "menu",
+                  "size": "xl",
+                  "indentation": 0,
+                  "items": [
+                    {
+                      "width": 12,
+                      "show_header": true,
+                      "type": "custom_quantities"
+                    }
+                  ]
                 },
-                "author": {
-                  "label": "Author",
-                  "level": 0,
-                  "size": "m"
+                {
+                  "width": 12,
+                  "show_header": true,
+                  "title": "Author",
+                  "type": "menu",
+                  "size": "lg",
+                  "indentation": 0,
+                  "items": [
+                    {
+                      "search_quantity": "authors.name",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "type": "histogram",
+                      "show_input": true,
+                      "x": {
+                        "search_quantity": "upload_create_time",
+                        "scale": "linear"
+                      },
+                      "y": {
+                        "scale": "linear"
+                      },
+                      "autorange": false,
+                      "width": 12,
+                      "show_header": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "external_db",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": false,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 5,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "datasets.dataset_name",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "datasets.doi",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    }
+                  ]
                 },
-                "metadata": {
-                  "label": "Visibility / IDs",
-                  "level": 0,
-                  "size": "s"
+                {
+                  "width": 12,
+                  "show_header": true,
+                  "title": "Visibility / IDs",
+                  "type": "menu",
+                  "size": "md",
+                  "indentation": 0,
+                  "items": [
+                    {
+                      "width": 12,
+                      "show_header": true,
+                      "type": "visibility"
+                    },
+                    {
+                      "search_quantity": "entry_id",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "upload_id",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "upload_name",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.material.material_id",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "datasets.dataset_id",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "width": 12,
+                      "show_header": true,
+                      "type": "definitions"
+                    }
+                  ]
                 }
-              }
+              ]
             },
             "filters": {
               "include": [
                 "*#nomad_aitoolkit.schema.AIToolkitNotebook"
               ]
             },
+            "search_quantities": {
+              "include": [
+                "*#nomad_aitoolkit.schema.AIToolkitNotebook"
+              ]
+            },
             "dashboard": {
               "widgets": [
                 {
+                  "search_quantity": "data.category#nomad_aitoolkit.schema.AIToolkitNotebook",
                   "type": "terms",
+                  "scale": "linear",
+                  "show_input": true,
                   "layout": {
                     "xxl": {
                       "h": 6,
@@ -3007,14 +7769,14 @@ window.nomadEnv = {
                       "minH": 3,
                       "minW": 3
                     }
-                  },
-                  "quantity": "data.category#nomad_aitoolkit.schema.AIToolkitNotebook",
-                  "scale": "linear",
-                  "showinput": true
+                  }
                 },
                 {
-                  "title": "Methods",
+                  "search_quantity": "data.methods.name#nomad_aitoolkit.schema.AIToolkitNotebook",
                   "type": "terms",
+                  "scale": "linear",
+                  "show_input": true,
+                  "title": "Methods",
                   "layout": {
                     "xxl": {
                       "h": 6,
@@ -3056,14 +7818,14 @@ window.nomadEnv = {
                       "minH": 3,
                       "minW": 3
                     }
-                  },
-                  "quantity": "data.methods.name#nomad_aitoolkit.schema.AIToolkitNotebook",
-                  "scale": "linear",
-                  "showinput": true
+                  }
                 },
                 {
-                  "title": "Systems",
+                  "search_quantity": "data.systems.name#nomad_aitoolkit.schema.AIToolkitNotebook",
                   "type": "terms",
+                  "scale": "linear",
+                  "show_input": true,
+                  "title": "Systems",
                   "layout": {
                     "xxl": {
                       "h": 6,
@@ -3104,11 +7866,8 @@ window.nomadEnv = {
                       "y": 0,
                       "minH": 3,
                       "minW": 3
-                    }
-                  },
-                  "quantity": "data.systems.name#nomad_aitoolkit.schema.AIToolkitNotebook",
-                  "scale": "linear",
-                  "showinput": true
+                    }
+                  }
                 }
               ]
             },
@@ -3198,44 +7957,479 @@ window.nomadEnv = {
                 "enabled": true
               }
             },
-            "filter_menus": {
-              "options": {
-                "material": {
-                  "label": "Material",
-                  "level": 0,
-                  "size": "s"
+            "menu": {
+              "width": 12,
+              "show_header": true,
+              "title": "Filters",
+              "type": "menu",
+              "size": "sm",
+              "indentation": 0,
+              "items": [
+                {
+                  "width": 12,
+                  "show_header": true,
+                  "title": "Material",
+                  "type": "menu",
+                  "size": "md",
+                  "indentation": 0
                 },
-                "elements": {
-                  "label": "Elements / Formula",
-                  "level": 1,
-                  "size": "xl"
+                {
+                  "width": 12,
+                  "show_header": true,
+                  "title": "Elements / Formula",
+                  "type": "menu",
+                  "size": "xxl",
+                  "indentation": 1,
+                  "items": [
+                    {
+                      "type": "periodic_table",
+                      "search_quantity": "results.material.elements",
+                      "scale": "linear",
+                      "width": 12,
+                      "show_header": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.material.chemical_formula_hill",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 6,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.material.chemical_formula_iupac",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 6,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.material.chemical_formula_reduced",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 6,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.material.chemical_formula_anonymous",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 6,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "type": "histogram",
+                      "show_input": true,
+                      "x": {
+                        "search_quantity": "results.material.n_elements",
+                        "scale": "linear"
+                      },
+                      "y": {
+                        "scale": "linear"
+                      },
+                      "autorange": false,
+                      "width": 12,
+                      "show_header": true,
+                      "show_statistics": true
+                    }
+                  ]
                 },
-                "structure": {
-                  "label": "Structure",
-                  "level": 1,
-                  "size": "s"
+                {
+                  "width": 12,
+                  "show_header": true,
+                  "title": "Structure",
+                  "type": "menu",
+                  "size": "md",
+                  "indentation": 1,
+                  "items": [
+                    {
+                      "search_quantity": "results.material.structural_type",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": false,
+                      "width": 12,
+                      "show_header": true,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.material.symmetry.bravais_lattice",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": false,
+                      "width": 12,
+                      "show_header": true,
+                      "n_columns": 2,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.material.symmetry.crystal_system",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": false,
+                      "width": 12,
+                      "show_header": true,
+                      "n_columns": 2,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.material.symmetry.space_group_symbol",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.material.symmetry.structure_name",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 5,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.material.symmetry.strukturbericht_designation",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.material.symmetry.point_group",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.material.symmetry.hall_symbol",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.material.symmetry.prototype_aflow_id",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    }
+                  ]
                 },
-                "electronic": {
-                  "label": "Electronic Properties",
-                  "level": 0,
-                  "size": "s"
+                {
+                  "width": 12,
+                  "show_header": true,
+                  "title": "Electronic Properties",
+                  "type": "menu",
+                  "size": "md",
+                  "indentation": 0,
+                  "items": [
+                    {
+                      "search_quantity": "electronic_properties",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": false,
+                      "width": 12,
+                      "show_header": true,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "width": 12,
+                      "show_header": true,
+                      "type": "nested_object",
+                      "path": "results.properties.electronic.band_structure_electronic.band_gap",
+                      "items": [
+                        {
+                          "search_quantity": "results.properties.electronic.band_structure_electronic.band_gap.type",
+                          "type": "terms",
+                          "scale": "linear",
+                          "show_input": false,
+                          "width": 12,
+                          "show_header": true,
+                          "options": 2,
+                          "n_columns": 1,
+                          "sort_static": true,
+                          "show_statistics": true
+                        },
+                        {
+                          "type": "histogram",
+                          "show_input": true,
+                          "x": {
+                            "search_quantity": "results.properties.electronic.band_structure_electronic.band_gap.value",
+                            "scale": "linear"
+                          },
+                          "y": {
+                            "scale": "linear"
+                          },
+                          "autorange": false,
+                          "width": 12,
+                          "show_header": true,
+                          "show_statistics": true
+                        }
+                      ]
+                    },
+                    {
+                      "width": 12,
+                      "show_header": true,
+                      "type": "nested_object",
+                      "path": "results.properties.electronic.band_structure_electronic",
+                      "items": [
+                        {
+                          "search_quantity": "results.properties.electronic.band_structure_electronic.spin_polarized",
+                          "type": "terms",
+                          "scale": "linear",
+                          "show_input": false,
+                          "width": 12,
+                          "show_header": true,
+                          "n_columns": 1,
+                          "sort_static": true,
+                          "show_statistics": true
+                        }
+                      ]
+                    },
+                    {
+                      "width": 12,
+                      "show_header": true,
+                      "type": "nested_object",
+                      "path": "results.properties.electronic.dos_electronic",
+                      "items": [
+                        {
+                          "search_quantity": "results.properties.electronic.dos_electronic.spin_polarized",
+                          "type": "terms",
+                          "scale": "linear",
+                          "show_input": false,
+                          "width": 12,
+                          "show_header": true,
+                          "n_columns": 1,
+                          "sort_static": true,
+                          "show_statistics": true
+                        }
+                      ]
+                    }
+                  ]
                 },
-                "author": {
-                  "label": "Author / Origin / Dataset",
-                  "level": 0,
-                  "size": "m"
+                {
+                  "width": 12,
+                  "show_header": true,
+                  "title": "Author / Origin / Dataset",
+                  "type": "menu",
+                  "size": "lg",
+                  "indentation": 0,
+                  "items": [
+                    {
+                      "search_quantity": "authors.name",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "type": "histogram",
+                      "show_input": true,
+                      "x": {
+                        "search_quantity": "upload_create_time",
+                        "scale": "linear"
+                      },
+                      "y": {
+                        "scale": "linear"
+                      },
+                      "autorange": false,
+                      "width": 12,
+                      "show_header": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "external_db",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": false,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 5,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "datasets.dataset_name",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "datasets.doi",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    }
+                  ]
                 },
-                "metadata": {
-                  "label": "Visibility / IDs / Schema",
-                  "level": 0,
-                  "size": "s"
+                {
+                  "width": 12,
+                  "show_header": true,
+                  "title": "Visibility / IDs / Schema",
+                  "type": "menu",
+                  "size": "md",
+                  "indentation": 0,
+                  "items": [
+                    {
+                      "width": 12,
+                      "show_header": true,
+                      "type": "visibility"
+                    },
+                    {
+                      "search_quantity": "entry_id",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "upload_id",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "upload_name",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.material.material_id",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "datasets.dataset_id",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "width": 12,
+                      "show_header": true,
+                      "type": "definitions"
+                    }
+                  ]
                 },
-                "optimade": {
-                  "label": "Optimade",
-                  "level": 0,
-                  "size": "m"
+                {
+                  "width": 12,
+                  "show_header": true,
+                  "title": "Optimade",
+                  "type": "menu",
+                  "size": "lg",
+                  "indentation": 0,
+                  "items": [
+                    {
+                      "width": 12,
+                      "show_header": true,
+                      "type": "optimade"
+                    }
+                  ]
                 }
-              }
+              ]
             },
             "filters": {
               "exclude": [
@@ -3244,10 +8438,19 @@ window.nomadEnv = {
                 "combine"
               ]
             },
+            "search_quantities": {
+              "exclude": [
+                "mainfile",
+                "entry_name",
+                "combine"
+              ]
+            },
             "dashboard": {
               "widgets": [
                 {
-                  "type": "periodictable",
+                  "type": "periodic_table",
+                  "search_quantity": "results.material.elements",
+                  "scale": "linear",
                   "layout": {
                     "lg": {
                       "h": 9,
@@ -3289,13 +8492,15 @@ window.nomadEnv = {
                       "minH": 3,
                       "minW": 3
                     }
-                  },
-                  "quantity": "results.material.elements",
-                  "scale": "linear"
+                  }
                 },
                 {
-                  "title": "SBU type",
+                  "search_quantity": "results.material.topology.sbu_type",
                   "type": "terms",
+                  "scale": "linear",
+                  "show_input": true,
+                  "showinput": true,
+                  "title": "SBU type",
                   "layout": {
                     "lg": {
                       "h": 9,
@@ -3337,13 +8542,22 @@ window.nomadEnv = {
                       "minH": 3,
                       "minW": 3
                     }
-                  },
-                  "quantity": "results.material.topology.sbu_type",
-                  "scale": "linear",
-                  "showinput": true
+                  }
                 },
                 {
                   "type": "histogram",
+                  "show_input": true,
+                  "showinput": true,
+                  "x": {
+                    "search_quantity": "results.material.topology.pore_limiting_diameter",
+                    "scale": "linear"
+                  },
+                  "y": {
+                    "scale": "linear"
+                  },
+                  "autorange": false,
+                  "n_bins": 30,
+                  "nbins": 30,
                   "layout": {
                     "lg": {
                       "h": 5,
@@ -3385,21 +8599,22 @@ window.nomadEnv = {
                       "minH": 3,
                       "minW": 3
                     }
-                  },
+                  }
+                },
+                {
+                  "type": "histogram",
+                  "show_input": true,
+                  "showinput": true,
                   "x": {
-                    "quantity": "results.material.topology.pore_limiting_diameter",
+                    "search_quantity": "results.material.topology.largest_cavity_diameter",
                     "scale": "linear"
                   },
                   "y": {
                     "scale": "linear"
                   },
-                  "scale": "linear",
-                  "autorange": true,
-                  "showinput": true,
-                  "nbins": 30
-                },
-                {
-                  "type": "histogram",
+                  "autorange": false,
+                  "n_bins": 30,
+                  "nbins": 30,
                   "layout": {
                     "lg": {
                       "h": 5,
@@ -3441,21 +8656,22 @@ window.nomadEnv = {
                       "minH": 3,
                       "minW": 3
                     }
-                  },
+                  }
+                },
+                {
+                  "type": "histogram",
+                  "show_input": true,
+                  "showinput": true,
                   "x": {
-                    "quantity": "results.material.topology.largest_cavity_diameter",
+                    "search_quantity": "results.material.topology.accessible_surface_area",
                     "scale": "linear"
                   },
                   "y": {
                     "scale": "linear"
                   },
-                  "scale": "linear",
-                  "autorange": true,
-                  "showinput": true,
-                  "nbins": 30
-                },
-                {
-                  "type": "histogram",
+                  "autorange": false,
+                  "n_bins": 30,
+                  "nbins": 30,
                   "layout": {
                     "lg": {
                       "h": 5,
@@ -3497,21 +8713,22 @@ window.nomadEnv = {
                       "minH": 3,
                       "minW": 3
                     }
-                  },
+                  }
+                },
+                {
+                  "type": "histogram",
+                  "show_input": true,
+                  "showinput": true,
                   "x": {
-                    "quantity": "results.material.topology.accessible_surface_area",
+                    "search_quantity": "results.material.topology.void_fraction",
                     "scale": "linear"
                   },
                   "y": {
                     "scale": "linear"
                   },
-                  "scale": "linear",
-                  "autorange": true,
-                  "showinput": true,
-                  "nbins": 30
-                },
-                {
-                  "type": "histogram",
+                  "autorange": false,
+                  "n_bins": 30,
+                  "nbins": 30,
                   "layout": {
                     "lg": {
                       "h": 5,
@@ -3553,18 +8770,7 @@ window.nomadEnv = {
                       "minH": 3,
                       "minW": 3
                     }
-                  },
-                  "x": {
-                    "quantity": "results.material.topology.void_fraction",
-                    "scale": "linear"
-                  },
-                  "y": {
-                    "scale": "linear"
-                  },
-                  "scale": "linear",
-                  "autorange": true,
-                  "showinput": true,
-                  "nbins": 30
+                  }
                 }
               ]
             },
@@ -3781,59 +8987,764 @@ window.nomadEnv = {
                 "enabled": true
               }
             },
-            "filter_menus": {
-              "options": {
-                "material": {
-                  "label": "Absorber Material",
-                  "level": 0,
-                  "size": "s"
+            "menu": {
+              "width": 12,
+              "show_header": true,
+              "title": "Filters",
+              "type": "menu",
+              "size": "sm",
+              "indentation": 0,
+              "items": [
+                {
+                  "width": 12,
+                  "show_header": true,
+                  "title": "Absorber Material",
+                  "type": "menu",
+                  "size": "md"
                 },
-                "elements": {
-                  "label": "Elements / Formula",
-                  "level": 1,
-                  "size": "xl"
+                {
+                  "width": 12,
+                  "show_header": true,
+                  "title": "Elements / Formula",
+                  "type": "menu",
+                  "size": "xxl",
+                  "indentation": 1,
+                  "items": [
+                    {
+                      "type": "periodic_table",
+                      "search_quantity": "results.material.elements",
+                      "scale": "linear",
+                      "width": 12,
+                      "show_header": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.material.chemical_formula_hill",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 6,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.material.chemical_formula_iupac",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 6,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.material.chemical_formula_reduced",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 6,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.material.chemical_formula_anonymous",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 6,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "type": "histogram",
+                      "show_input": true,
+                      "x": {
+                        "search_quantity": "results.material.n_elements",
+                        "scale": "linear"
+                      },
+                      "y": {
+                        "scale": "linear"
+                      },
+                      "autorange": false,
+                      "width": 12,
+                      "show_header": true,
+                      "show_statistics": true
+                    }
+                  ]
                 },
-                "structure": {
-                  "label": "Structure / Symmetry",
-                  "level": 1,
-                  "size": "s"
+                {
+                  "width": 12,
+                  "show_header": true,
+                  "title": "Structure / Symmetry",
+                  "type": "menu",
+                  "size": "md",
+                  "indentation": 1,
+                  "items": [
+                    {
+                      "search_quantity": "results.material.structural_type",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": false,
+                      "width": 12,
+                      "show_header": true,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.material.symmetry.bravais_lattice",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": false,
+                      "width": 12,
+                      "show_header": true,
+                      "n_columns": 2,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.material.symmetry.crystal_system",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": false,
+                      "width": 12,
+                      "show_header": true,
+                      "n_columns": 2,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.material.symmetry.space_group_symbol",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.material.symmetry.structure_name",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 5,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.material.symmetry.strukturbericht_designation",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.material.symmetry.point_group",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.material.symmetry.hall_symbol",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.material.symmetry.prototype_aflow_id",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    }
+                  ]
                 },
-                "electronic": {
-                  "label": "Electronic Properties",
-                  "level": 0,
-                  "size": "s"
+                {
+                  "width": 12,
+                  "show_header": true,
+                  "title": "Electronic Properties",
+                  "type": "menu",
+                  "size": "md",
+                  "items": [
+                    {
+                      "search_quantity": "electronic_properties",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": false,
+                      "width": 12,
+                      "show_header": true,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "width": 12,
+                      "show_header": true,
+                      "type": "nested_object",
+                      "path": "results.properties.electronic.band_structure_electronic.band_gap",
+                      "items": [
+                        {
+                          "search_quantity": "results.properties.electronic.band_structure_electronic.band_gap.type",
+                          "type": "terms",
+                          "scale": "linear",
+                          "show_input": false,
+                          "width": 12,
+                          "show_header": true,
+                          "options": 2,
+                          "n_columns": 1,
+                          "sort_static": true,
+                          "show_statistics": true
+                        },
+                        {
+                          "type": "histogram",
+                          "show_input": true,
+                          "x": {
+                            "search_quantity": "results.properties.electronic.band_structure_electronic.band_gap.value",
+                            "scale": "linear"
+                          },
+                          "y": {
+                            "scale": "linear"
+                          },
+                          "autorange": false,
+                          "width": 12,
+                          "show_header": true,
+                          "show_statistics": true
+                        }
+                      ]
+                    },
+                    {
+                      "width": 12,
+                      "show_header": true,
+                      "type": "nested_object",
+                      "path": "results.properties.electronic.band_structure_electronic",
+                      "items": [
+                        {
+                          "search_quantity": "results.properties.electronic.band_structure_electronic.spin_polarized",
+                          "type": "terms",
+                          "scale": "linear",
+                          "show_input": false,
+                          "width": 12,
+                          "show_header": true,
+                          "n_columns": 1,
+                          "sort_static": true,
+                          "show_statistics": true
+                        }
+                      ]
+                    },
+                    {
+                      "width": 12,
+                      "show_header": true,
+                      "type": "nested_object",
+                      "path": "results.properties.electronic.dos_electronic",
+                      "items": [
+                        {
+                          "search_quantity": "results.properties.electronic.dos_electronic.spin_polarized",
+                          "type": "terms",
+                          "scale": "linear",
+                          "show_input": false,
+                          "width": 12,
+                          "show_header": true,
+                          "n_columns": 1,
+                          "sort_static": true,
+                          "show_statistics": true
+                        }
+                      ]
+                    }
+                  ]
                 },
-                "solarcell": {
-                  "label": "Solar Cell Properties",
-                  "level": 0,
-                  "size": "s"
+                {
+                  "width": 12,
+                  "show_header": true,
+                  "title": "Solar Cell Properties",
+                  "type": "menu",
+                  "size": "md",
+                  "items": [
+                    {
+                      "type": "histogram",
+                      "show_input": true,
+                      "x": {
+                        "search_quantity": "results.properties.optoelectronic.solar_cell.efficiency",
+                        "scale": "linear"
+                      },
+                      "y": {
+                        "scale": "linear"
+                      },
+                      "autorange": false,
+                      "width": 12,
+                      "show_header": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "type": "histogram",
+                      "show_input": true,
+                      "x": {
+                        "search_quantity": "results.properties.optoelectronic.solar_cell.fill_factor",
+                        "scale": "linear"
+                      },
+                      "y": {
+                        "scale": "linear"
+                      },
+                      "autorange": false,
+                      "width": 12,
+                      "show_header": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "type": "histogram",
+                      "show_input": true,
+                      "x": {
+                        "search_quantity": "results.properties.optoelectronic.solar_cell.open_circuit_voltage",
+                        "scale": "linear"
+                      },
+                      "y": {
+                        "scale": "linear"
+                      },
+                      "autorange": false,
+                      "width": 12,
+                      "show_header": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "type": "histogram",
+                      "show_input": true,
+                      "x": {
+                        "search_quantity": "results.properties.optoelectronic.solar_cell.short_circuit_current_density",
+                        "scale": "linear"
+                      },
+                      "y": {
+                        "scale": "linear"
+                      },
+                      "autorange": false,
+                      "width": 12,
+                      "show_header": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "type": "histogram",
+                      "show_input": true,
+                      "x": {
+                        "search_quantity": "results.properties.optoelectronic.solar_cell.illumination_intensity",
+                        "scale": "linear"
+                      },
+                      "y": {
+                        "scale": "linear"
+                      },
+                      "autorange": false,
+                      "width": 12,
+                      "show_header": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "type": "histogram",
+                      "show_input": true,
+                      "x": {
+                        "search_quantity": "results.properties.optoelectronic.solar_cell.device_area",
+                        "scale": "linear"
+                      },
+                      "y": {
+                        "scale": "linear"
+                      },
+                      "autorange": false,
+                      "width": 12,
+                      "show_header": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.properties.optoelectronic.solar_cell.device_architecture",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.properties.optoelectronic.solar_cell.device_stack",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.properties.optoelectronic.solar_cell.absorber",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.properties.optoelectronic.solar_cell.absorber_fabrication",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.properties.optoelectronic.solar_cell.electron_transport_layer",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.properties.optoelectronic.solar_cell.hole_transport_layer",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.properties.optoelectronic.solar_cell.substrate",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.properties.optoelectronic.solar_cell.back_contact",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    }
+                  ]
                 },
-                "eln": {
-                  "label": "Electronic Lab Notebook",
-                  "level": 0,
-                  "size": "s"
+                {
+                  "width": 12,
+                  "show_header": true,
+                  "title": "Electronic Lab Notebook",
+                  "type": "menu",
+                  "size": "md",
+                  "items": [
+                    {
+                      "search_quantity": "results.eln.sections",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": false,
+                      "width": 12,
+                      "show_header": true,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.eln.tags",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": false,
+                      "width": 12,
+                      "show_header": true,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.eln.methods",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": false,
+                      "width": 12,
+                      "show_header": true,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.eln.instruments",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": false,
+                      "width": 12,
+                      "show_header": true,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.eln.names",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.eln.descriptions",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.eln.lab_ids",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    }
+                  ]
                 },
-                "custom_quantities": {
-                  "label": "User Defined Quantities",
-                  "level": 0,
-                  "size": "l"
+                {
+                  "width": 12,
+                  "show_header": true,
+                  "title": "User Defined Quantities",
+                  "type": "menu",
+                  "size": "xl",
+                  "items": [
+                    {
+                      "width": 12,
+                      "show_header": true,
+                      "type": "custom_quantities"
+                    }
+                  ]
                 },
-                "author": {
-                  "label": "Author / Origin / Dataset",
-                  "level": 0,
-                  "size": "m"
+                {
+                  "width": 12,
+                  "show_header": true,
+                  "title": "Author / Origin / Dataset",
+                  "type": "menu",
+                  "size": "lg",
+                  "items": [
+                    {
+                      "search_quantity": "authors.name",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "type": "histogram",
+                      "show_input": true,
+                      "x": {
+                        "search_quantity": "upload_create_time",
+                        "scale": "linear"
+                      },
+                      "y": {
+                        "scale": "linear"
+                      },
+                      "autorange": false,
+                      "width": 12,
+                      "show_header": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "external_db",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": false,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 5,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "datasets.dataset_name",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "datasets.doi",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    }
+                  ]
                 },
-                "metadata": {
-                  "label": "Visibility / IDs / Schema",
-                  "level": 0,
-                  "size": "s"
+                {
+                  "width": 12,
+                  "show_header": true,
+                  "title": "Visibility / IDs / Schema",
+                  "type": "menu",
+                  "size": "md",
+                  "items": [
+                    {
+                      "width": 12,
+                      "show_header": true,
+                      "type": "visibility"
+                    },
+                    {
+                      "search_quantity": "entry_id",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "upload_id",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "upload_name",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "results.material.material_id",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "search_quantity": "datasets.dataset_id",
+                      "type": "terms",
+                      "scale": "linear",
+                      "show_input": true,
+                      "width": 12,
+                      "show_header": true,
+                      "options": 0,
+                      "n_columns": 1,
+                      "sort_static": true,
+                      "show_statistics": true
+                    },
+                    {
+                      "width": 12,
+                      "show_header": true,
+                      "type": "definitions"
+                    }
+                  ]
                 },
-                "optimade": {
-                  "label": "Optimade",
-                  "level": 0,
-                  "size": "m"
+                {
+                  "width": 12,
+                  "show_header": true,
+                  "title": "Optimade",
+                  "type": "menu",
+                  "size": "lg",
+                  "items": [
+                    {
+                      "width": 12,
+                      "show_header": true,
+                      "type": "optimade"
+                    }
+                  ]
                 }
-              }
+              ]
             },
             "filters": {
               "include": [
@@ -3845,10 +9756,22 @@ window.nomadEnv = {
                 "combine"
               ]
             },
+            "search_quantities": {
+              "include": [
+                "*#perovskite_solar_cell_database.schema.PerovskiteSolarCell"
+              ],
+              "exclude": [
+                "mainfile",
+                "entry_name",
+                "combine"
+              ]
+            },
             "dashboard": {
               "widgets": [
                 {
                   "type": "periodictable",
+                  "search_quantity": "results.material.elements",
+                  "scale": "linear",
                   "layout": {
                     "lg": {
                       "h": 8,
@@ -3890,9 +9813,7 @@ window.nomadEnv = {
                       "minH": 8,
                       "minW": 12
                     }
-                  },
-                  "quantity": "results.material.elements",
-                  "scale": "linear"
+                  }
                 },
                 {
                   "type": "scatterplot",
@@ -3939,18 +9860,18 @@ window.nomadEnv = {
                     }
                   },
                   "x": {
-                    "quantity": "results.properties.optoelectronic.solar_cell.open_circuit_voltage",
+                    "search_quantity": "results.properties.optoelectronic.solar_cell.open_circuit_voltage",
                     "scale": "linear"
                   },
                   "y": {
                     "title": "Efficiency (%)",
-                    "quantity": "results.properties.optoelectronic.solar_cell.efficiency",
+                    "search_quantity": "results.properties.optoelectronic.solar_cell.efficiency",
                     "scale": "linear"
                   },
                   "markers": {
                     "color": {
                       "unit": "mA/cm^2",
-                      "quantity": "results.properties.optoelectronic.solar_cell.short_circuit_current_density",
+                      "search_quantity": "results.properties.optoelectronic.solar_cell.short_circuit_current_density",
                       "scale": "linear"
                     }
                   },
@@ -4002,17 +9923,17 @@ window.nomadEnv = {
                     }
                   },
                   "x": {
-                    "quantity": "results.properties.optoelectronic.solar_cell.open_circuit_voltage",
+                    "search_quantity": "results.properties.optoelectronic.solar_cell.open_circuit_voltage",
                     "scale": "linear"
                   },
                   "y": {
                     "title": "Efficiency (%)",
-                    "quantity": "results.properties.optoelectronic.solar_cell.efficiency",
+                    "search_quantity": "results.properties.optoelectronic.solar_cell.efficiency",
                     "scale": "linear"
                   },
                   "markers": {
                     "color": {
-                      "quantity": "results.properties.optoelectronic.solar_cell.device_architecture",
+                      "search_quantity": "results.properties.optoelectronic.solar_cell.device_architecture",
                       "scale": "linear"
                     }
                   },
@@ -4020,7 +9941,11 @@ window.nomadEnv = {
                   "autorange": true
                 },
                 {
+                  "search_quantity": "results.properties.optoelectronic.solar_cell.device_stack",
                   "type": "terms",
+                  "scale": "linear",
+                  "show_input": true,
+                  "showinput": true,
                   "layout": {
                     "lg": {
                       "h": 6,
@@ -4062,13 +9987,22 @@ window.nomadEnv = {
                       "minH": 3,
                       "minW": 3
                     }
-                  },
-                  "quantity": "results.properties.optoelectronic.solar_cell.device_stack",
-                  "scale": "linear",
-                  "showinput": true
+                  }
                 },
                 {
                   "type": "histogram",
+                  "show_input": true,
+                  "showinput": true,
+                  "x": {
+                    "search_quantity": "results.properties.optoelectronic.solar_cell.illumination_intensity",
+                    "scale": "linear"
+                  },
+                  "y": {
+                    "scale": "1/4"
+                  },
+                  "autorange": true,
+                  "n_bins": 30,
+                  "nbins": 30,
                   "layout": {
                     "lg": {
                       "h": 4,
@@ -4110,21 +10044,14 @@ window.nomadEnv = {
                       "minH": 3,
                       "minW": 3
                     }
-                  },
-                  "x": {
-                    "quantity": "results.properties.optoelectronic.solar_cell.illumination_intensity",
-                    "scale": "linear"
-                  },
-                  "y": {
-                    "scale": "1/4"
-                  },
-                  "scale": "linear",
-                  "autorange": true,
-                  "showinput": true,
-                  "nbins": 30
+                  }
                 },
                 {
+                  "search_quantity": "results.properties.optoelectronic.solar_cell.absorber_fabrication",
                   "type": "terms",
+                  "scale": "linear",
+                  "show_input": true,
+                  "showinput": true,
                   "layout": {
                     "lg": {
                       "h": 6,
@@ -4166,14 +10093,23 @@ window.nomadEnv = {
                       "minH": 3,
                       "minW": 3
                     }
-                  },
-                  "quantity": "results.properties.optoelectronic.solar_cell.absorber_fabrication",
-                  "scale": "linear",
-                  "showinput": true
+                  }
                 },
                 {
-                  "title": "Band gap",
                   "type": "histogram",
+                  "show_input": false,
+                  "showinput": false,
+                  "x": {
+                    "search_quantity": "results.properties.electronic.band_structure_electronic.band_gap.value",
+                    "scale": "linear"
+                  },
+                  "y": {
+                    "scale": "1/4"
+                  },
+                  "autorange": false,
+                  "n_bins": 30,
+                  "nbins": 30,
+                  "title": "Band gap",
                   "layout": {
                     "lg": {
                       "h": 4,
@@ -4215,21 +10151,14 @@ window.nomadEnv = {
                       "minH": 3,
                       "minW": 8
                     }
-                  },
-                  "x": {
-                    "quantity": "results.properties.electronic.band_structure_electronic.band_gap.value",
-                    "scale": "linear"
-                  },
-                  "y": {
-                    "scale": "1/4"
-                  },
-                  "scale": "linear",
-                  "autorange": false,
-                  "showinput": false,
-                  "nbins": 30
+                  }
                 },
                 {
+                  "search_quantity": "results.properties.optoelectronic.solar_cell.electron_transport_layer",
                   "type": "terms",
+                  "scale": "linear",
+                  "show_input": true,
+                  "showinput": true,
                   "layout": {
                     "lg": {
                       "h": 6,
@@ -4271,13 +10200,14 @@ window.nomadEnv = {
                       "minH": 3,
                       "minW": 3
                     }
-                  },
-                  "quantity": "results.properties.optoelectronic.solar_cell.electron_transport_layer",
-                  "scale": "linear",
-                  "showinput": true
+                  }
                 },
                 {
+                  "search_quantity": "results.properties.optoelectronic.solar_cell.hole_transport_layer",
                   "type": "terms",
+                  "scale": "linear",
+                  "show_input": true,
+                  "showinput": true,
                   "layout": {
                     "lg": {
                       "h": 6,
@@ -4319,10 +10249,7 @@ window.nomadEnv = {
                       "minH": 3,
                       "minW": 3
                     }
-                  },
-                  "quantity": "results.properties.optoelectronic.solar_cell.hole_transport_layer",
-                  "scale": "linear",
-                  "showinput": true
+                  }
                 }
               ]
             },
diff --git a/nomad/config/defaults.yaml b/nomad/config/defaults.yaml
index da60ca06e2..53820b6b7f 100644
--- a/nomad/config/defaults.yaml
+++ b/nomad/config/defaults.yaml
@@ -857,6 +857,7 @@ ui:
             optimade:
               label: Optimade
               size: m
+
       calculations:
         label: Calculations
         path: calculations
@@ -983,7 +984,7 @@ ui:
               xxl: {h: 9, minH: 3, minW: 3, w: 6, x: 30, y: 0}
             quantity: results.material.symmetry.space_group_symbol
             scale: linear
-            showinput: true
+            show_input: true
             type: terms
           - layout:
               lg: {h: 6, minH: 3, minW: 3, w: 5, x: 19, y: 0}
@@ -993,7 +994,7 @@ ui:
               xxl: {h: 9, minH: 3, minW: 3, w: 6, x: 19, y: 0}
             quantity: results.material.structural_type
             scale: log
-            showinput: false
+            show_input: false
             type: terms
           - layout:
               lg: {h: 6, minH: 3, minW: 3, w: 5, x: 14, y: 0}
@@ -1003,7 +1004,7 @@ ui:
               xxl: {h: 9, minH: 3, minW: 3, w: 6, x: 13, y: 0}
             quantity: results.method.simulation.program_name
             scale: log
-            showinput: true
+            show_input: true
             type: terms
           - layout:
               lg: {h: 5, minH: 3, minW: 3, w: 5, x: 14, y: 6}
@@ -1013,7 +1014,7 @@ ui:
               xxl: {h: 9, minH: 3, minW: 3, w: 5, x: 25, y: 0}
             quantity: results.material.symmetry.crystal_system
             scale: linear
-            showinput: false
+            show_input: false
             type: terms
       materials:
         label: Materials
diff --git a/nomad/config/models/ui.py b/nomad/config/models/ui.py
index bc58cbb0a3..d92e549ee9 100644
--- a/nomad/config/models/ui.py
+++ b/nomad/config/models/ui.py
@@ -31,6 +31,21 @@ from .common import (
 )
 
 
+class ScaleEnum(str, Enum):
+    LINEAR = 'linear'
+    LOG = 'log'
+    # TODO: The following should possibly be deprecated.
+    POW1 = 'linear'
+    POW2 = '1/2'
+    POW4 = '1/4'
+    POW8 = '1/8'
+
+
+class ScaleEnumPlot(str, Enum):
+    LINEAR = 'linear'
+    LOG = 'log'
+
+
 class UnitSystemUnit(ConfigBaseModel):
     definition: str = Field(
         description="""
@@ -351,10 +366,12 @@ class Rows(ConfigBaseModel):
     selection: RowSelection
 
 
+# Deprecated
 class FilterMenuActionEnum(str, Enum):
     CHECKBOX = 'checkbox'
 
 
+# Deprecated
 class FilterMenuAction(ConfigBaseModel):
     """Contains definition for an action in the filter menu."""
 
@@ -362,12 +379,14 @@ class FilterMenuAction(ConfigBaseModel):
     label: str = Field(description='Label to show.')
 
 
+# Deprecated
 class FilterMenuActionCheckbox(FilterMenuAction):
     """Contains definition for checkbox action in the filter menu."""
 
     quantity: str = Field(description='Targeted quantity')
 
 
+# Deprecated
 class FilterMenuActions(Options):
     """Contains filter menu action definitions and controls their availability."""
 
@@ -376,6 +395,7 @@ class FilterMenuActions(Options):
     )
 
 
+# Deprecated
 class FilterMenuSizeEnum(str, Enum):
     S = 's'
     M = 'm'
@@ -383,6 +403,7 @@ class FilterMenuSizeEnum(str, Enum):
     XL = 'xl'
 
 
+# Deprecated
 class FilterMenu(ConfigBaseModel):
     """Defines the layout and functionality for a filter menu."""
 
@@ -394,6 +415,7 @@ class FilterMenu(ConfigBaseModel):
     actions: Optional[FilterMenuActions]
 
 
+# Deprecated
 class FilterMenus(Options):
     """Contains filter menu definitions and controls their availability."""
 
@@ -402,11 +424,421 @@ class FilterMenus(Options):
     )
 
 
-class Filters(OptionsGlob):
-    """Controls the availability of filters in the app. Filters are pieces of
-    (meta)info than can be queried in the search interface of the app, but also
-    targeted in the rest of the app configuration. The `include` and `exlude`
-    attributes can use glob syntax to target metainfo, e.g. `results.*` or
+# NOTE: Once the old power scaling options (1/2, 1/4, 1/8) are deprecated, the
+# axis models here can be simplified.
+class AxisScale(ConfigBaseModel):
+    """Basic configuration for a plot axis."""
+
+    scale: Optional[ScaleEnum] = Field(
+        ScaleEnum.LINEAR,
+        description="""Defines the axis scaling. Defaults to linear scaling.""",
+    )
+
+
+class AxisQuantity(ConfigBaseModel):
+    """Configuration for a plot axis."""
+
+    title: Optional[str] = Field(description="""Custom title to show for the axis.""")
+    unit: Optional[str] = Field(
+        description="""Custom unit used for displaying the values."""
+    )
+    quantity: Optional[str] = Field(
+        deprecated='The "quantity" field is deprecated, use "search_quantity" instead.'
+    )
+    search_quantity: str = Field(
+        description="""
+        Path of the targeted search quantity. Note that you can most of the features
+        JMESPath syntax here to further specify a selection of values. This
+        becomes especially useful when dealing with repeated sections or
+        statistical values.
+        """
+    )
+
+    @root_validator(pre=True)
+    def _validate(cls, values):
+        # Backwards compatibility for quantity.
+        quantity = values.get('quantity')
+        search_quantity = values.get('search_quantity')
+        if quantity is not None and search_quantity is None:
+            values['search_quantity'] = quantity
+            del values['quantity']
+
+        return values
+
+
+class Axis(AxisScale, AxisQuantity):
+    """Configuration for a plot axis with limited scaling options."""
+
+
+class TermsBase(ConfigBaseModel):
+    """Base model for configuring terms components."""
+
+    quantity: Optional[str] = Field(
+        deprecated='The "quantity" field is deprecated, use "search_quantity" instead.'
+    )
+    search_quantity: str = Field(description='The targeted search quantity.')
+    type: Literal['terms'] = Field(
+        description='Set as `terms` to get this type.',
+    )
+    scale: ScaleEnum = Field(ScaleEnum.LINEAR, description='Statistics scaling.')
+    show_input: bool = Field(True, description='Whether to show text input field.')
+    showinput: Optional[bool] = Field(
+        deprecated='The "showinput" field is deprecated, use "show_input" instead.'
+    )
+
+    @root_validator(pre=True)
+    def _validate(cls, values):
+        values['type'] = 'terms'
+
+        # Backwards compatibility for showinput.
+        showinput = values.get('showinput')
+        if showinput is not None:
+            values['show_input'] = showinput
+
+        # Backwards compatibility for quantity.
+        quantity = values.get('quantity')
+        search_quantity = values.get('search_quantity')
+        if quantity is not None and search_quantity is None:
+            values['search_quantity'] = quantity
+            del values['quantity']
+
+        return values
+
+
+class HistogramBase(ConfigBaseModel):
+    """Base model for configuring histogram components."""
+
+    type: Literal['histogram'] = Field(
+        description='Set as `histogram` to get this widget type.'
+    )
+    quantity: Optional[str] = Field(
+        deprecated='The "quantity" field is deprecated, use "x.search_quantity" instead.'
+    )
+    scale: Optional[ScaleEnum] = Field(
+        deprecated='The "scale" field is deprecated, use "y.scale" instead.'
+    )
+    show_input: bool = Field(True, description='Whether to show text input field.')
+    showinput: Optional[bool] = Field(
+        deprecated='The "showinput" field is deprecated, use "show_input" instead.'
+    )
+
+    x: Union[Axis, str] = Field(
+        description='Configures the information source and display options for the x-axis.'
+    )
+    y: Union[AxisScale, str] = Field(
+        description='Configures the information source and display options for the y-axis.'
+    )
+    autorange: bool = Field(
+        False,
+        description='Whether to automatically set the range according to the data limits.',
+    )
+    n_bins: Optional[int] = Field(
+        description="""
+        Maximum number of histogram bins. Notice that the actual number of bins
+        may be smaller if there are fewer data items available.
+        """
+    )
+    nbins: Optional[int] = Field(
+        deprecated='The "nbins" field is deprecated, use "n_bins" instead.'
+    )
+
+    @root_validator(pre=True)
+    def _validate(cls, values):
+        values['type'] = 'histogram'
+
+        # Backwards compatibility for nbins."""
+        nbins = values.get('nbins')
+        if nbins is not None:
+            values['n_bins'] = nbins
+
+        # Backwards compatibility for showinput."""
+        showinput = values.get('showinput')
+        if showinput is not None:
+            values['show_input'] = showinput
+
+        # x backwards compatibility
+        x = values.get('x', {})
+        if isinstance(x, str):
+            x = {'search_quantity': x}
+        if isinstance(x, dict):
+            quantity = values.get('quantity')
+            if quantity and not x.get('search_quantity'):
+                x['search_quantity'] = quantity
+                del values['quantity']
+            values['x'] = x
+
+        # y backwards compatibility
+        y = values.get('y', {})
+        if isinstance(y, dict):
+            scale = values.get('scale')
+            if scale:
+                y['scale'] = scale
+                del values['scale']
+            values['y'] = y
+
+        return values
+
+
+class PeriodicTableBase(ConfigBaseModel):
+    """Base model for configuring periodic table components."""
+
+    type: Literal['periodic_table'] = Field(
+        description='Set as `periodic_table` to get this widget type.'
+    )
+    quantity: Optional[str] = Field(
+        deprecated='The "quantity" field is deprecated, use "search_quantity" instead.'
+    )
+    search_quantity: str = Field(description='The targeted search quantity.')
+    scale: Optional[ScaleEnum] = Field(
+        ScaleEnum.LINEAR, description='Statistics scaling.'
+    )
+
+    @root_validator(pre=True)
+    def _validate(cls, values):
+        values['type'] = 'periodic_table'
+
+        # Backwards compatibility for quantity.
+        quantity = values.get('quantity')
+        search_quantity = values.get('search_quantity')
+        if quantity is not None and search_quantity is None:
+            values['search_quantity'] = quantity
+            del values['quantity']
+
+        return values
+
+
+class MenuSizeEnum(str, Enum):
+    XS = 'xs'
+    SM = 'sm'
+    MD = 'md'
+    LG = 'lg'
+    XL = 'xl'
+    XXL = 'xxl'
+
+
+class MenuItem(ConfigBaseModel):
+    width: int = Field(
+        12,
+        description='Width of the item, 12 means maximum width. Note that the menu size can be changed.',
+    )
+    show_header: bool = Field(True, description='Whether to show the header.')
+    title: Optional[str] = Field(description='Custom item title.')
+
+
+class MenuItemOption(ConfigBaseModel):
+    """Represents an option shown for a filter."""
+
+    label: Optional[str] = Field(description='The label to show for this option.')
+    description: Optional[str] = Field(
+        description='Detailed description for this option.'
+    )
+
+
+class MenuItemTerms(MenuItem, TermsBase):
+    """Menu item that shows a list of text values from e.g. `str` or `MEnum`
+    quantities.
+    """
+
+    options: Optional[Union[int, Dict[str, MenuItemOption]]] = Field(
+        description="""
+        Used to control the displayed options:
+
+         - If not specified, sensible default options are shown based on the
+           definition. For enum fields all of the defined options are shown,
+           whereas for generic string fields the top 5 options are shown.
+
+         - If a number is specified, that many options are dynamically fetched
+           in order of occurrence. Set to 0 to completely disable options.
+
+         - If a dictionary of str + MenuItemOption pairs is given, only these
+           options will be shown.
+        """
+    )
+    n_columns: int = Field(
+        1,
+        description='The number of columns to use when displaying the options.',
+    )
+    sort_static: bool = Field(
+        True,
+        description="""
+        Whether to sort static options by their occurrence in the data. Options
+        are static if they are read from the enum options of the field or if
+        they are explicitly given as a dictionary in 'options'.
+        """,
+    )
+    show_statistics: bool = Field(
+        True, description='Whether to show statistics for the options.'
+    )
+
+
+class MenuItemHistogram(MenuItem, HistogramBase):
+    """Menu item that shows a histogram for numerical or timestamp quantities."""
+
+    show_statistics: bool = Field(
+        True, description='Whether to show the full histogram, or just a range slider.'
+    )
+
+
+class MenuItemPeriodicTable(MenuItem, PeriodicTableBase):
+    """Menu item that shows a periodic table built from values stored into a
+    text quantity.
+    """
+
+    show_statistics: bool = Field(
+        True, description='Whether to show statistics for the options.'
+    )
+
+
+class MenuItemVisibility(MenuItem):
+    """Menu item that shows a radio button that can be used to change the visiblity."""
+
+    type: Literal['visibility'] = Field(
+        description='Set as `visibility` to get this menu item type.',
+    )
+
+    @root_validator(pre=True)
+    def _validate(cls, values):
+        values['type'] = 'visibility'
+        return values
+
+
+class MenuItemDefinitions(MenuItem):
+    """Menu item that shows a tree for filtering data by the presence of definitions."""
+
+    type: Literal['definitions'] = Field(
+        description='Set as `definitions` to get this menu item type.',
+    )
+
+    @root_validator(pre=True)
+    def _validate(cls, values):
+        values['type'] = 'definitions'
+        return values
+
+
+class MenuItemOptimade(MenuItem):
+    """Menu item that shows a dialog for entering OPTIMADE queries."""
+
+    type: Literal['optimade'] = Field(
+        description='Set as `optimade` to get this menu item type.',
+    )
+
+    @root_validator(pre=True)
+    def _validate(cls, values):
+        values['type'] = 'optimade'
+        return values
+
+
+class MenuItemCustomQuantities(MenuItem):
+    """Menu item that shows a search dialog for filtering by custom quantities
+    coming from all different custom schemas, including YAML and Python schemas.
+    Will only show quantities that have been populated in the data.
+    """
+
+    type: Literal['custom_quantities'] = Field(
+        description='Set as `custom_quantities` to get this menu item type.',
+    )
+
+    @root_validator(pre=True)
+    def _validate(cls, values):
+        values['type'] = 'custom_quantities'
+        return values
+
+
+# The 'discriminated union' feature of Pydantic is used here:
+# https://docs.pydantic.dev/usage/types/#discriminated-unions-aka-tagged-unions
+MenuItemTypeNested = Annotated[
+    Union[
+        MenuItemTerms,
+        MenuItemHistogram,
+        MenuItemPeriodicTable,
+        MenuItemVisibility,
+        MenuItemDefinitions,
+        MenuItemOptimade,
+        MenuItemCustomQuantities,
+    ],
+    Field(discriminator='type'),
+]
+
+
+class MenuItemNestedObject(MenuItem):
+    """Menu item that can be used to wrap several subitems into a nested object.
+    By wrapping items with this class the query for them is performed as an
+    Elasticsearch nested query:
+    https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-nested-query.html.
+    Note that you cannot yet use nested queries for search quantities
+    originating from custom schemas.
+    """
+
+    type: Literal['nested_object'] = Field(
+        description='Set as `nested_object` to get this menu item type.',
+    )
+    path: str = Field(
+        description='Path of the nested object. Typically a section name.'
+    )
+    items: Optional[List[MenuItemTypeNested]] = Field(
+        description='Items that are grouped by this nested object.'
+    )
+
+    @root_validator(pre=True)
+    def _validate(cls, values):
+        values['type'] = 'nested_object'
+        return values
+
+
+# The 'discriminated union' feature of Pydantic is used here:
+# https://docs.pydantic.dev/usage/types/#discriminated-unions-aka-tagged-unions
+MenuItemType = Annotated[
+    Union[
+        MenuItemTerms,
+        MenuItemHistogram,
+        MenuItemPeriodicTable,
+        MenuItemNestedObject,
+        MenuItemVisibility,
+        MenuItemDefinitions,
+        MenuItemOptimade,
+        MenuItemCustomQuantities,
+        'Menu',
+    ],
+    Field(discriminator='type'),
+]
+
+
+class Menu(MenuItem):
+    """Defines a menu that is shown on the left side of the search interface.
+    Menus have a controllable width, and contains items. Items in the menu are
+    displayed on a 12-based grid and you can control the width of each item by
+    using the `width` field. You can also nest menus within each other.
+    """
+
+    type: Literal['menu'] = Field(
+        description='Set as `nested_object` to get this menu item type.',
+    )
+    size: Optional[Union[MenuSizeEnum, str]] = Field(
+        MenuSizeEnum.SM,
+        description="""
+        Size of the menu. Either use presets as defined by MenuSizeEnum,
+        or then provide valid CSS widths.
+        """,
+    )
+    indentation: Optional[int] = Field(0, description='Indentation level for the menu.')
+    items: Optional[List[MenuItemType]] = Field(
+        description='List of items in the menu.'
+    )
+
+    @root_validator(pre=True)
+    def _validate(cls, values):
+        values['type'] = 'menu'
+        return values
+
+
+class SearchQuantities(OptionsGlob):
+    """Controls the quantities that are available in the search interface.
+    Search quantities correspond to pieces of information that can be queried in
+    the search interface of the app, but also targeted in the rest of the app
+    configuration. You can load quantities from custom schemas as search
+    quantities, but note that not all quantities will be loaded: only scalar
+    values are supported at the moment. The `include` and `exlude` attributes
+    can use glob syntax to target metainfo, e.g. `results.*` or
     `*.#myschema.schema.MySchema`.
     """
 
@@ -422,6 +854,10 @@ class Filters(OptionsGlob):
     )
 
 
+class Filters(SearchQuantities):
+    """Alias for SearchQuantities."""
+
+
 class SearchSyntaxes(ConfigBaseModel):
     """Controls the availability of different search syntaxes. These syntaxes
     determine how raw user input in e.g. the search bar is parsed into queries
@@ -455,21 +891,6 @@ class Layout(ConfigBaseModel):
     minW: Optional[int] = Field(3, description='Minimum width in grid units.')
 
 
-class ScaleEnum(str, Enum):
-    LINEAR = 'linear'
-    LOG = 'log'
-    # TODO: The following should possibly be deprecated.
-    POW1 = 'linear'
-    POW2 = '1/2'
-    POW4 = '1/4'
-    POW8 = '1/8'
-
-
-class ScaleEnumPlot(str, Enum):
-    LINEAR = 'linear'
-    LOG = 'log'
-
-
 class BreakpointEnum(str, Enum):
     SM = 'sm'
     MD = 'md'
@@ -478,38 +899,6 @@ class BreakpointEnum(str, Enum):
     XXL = 'xxl'
 
 
-# NOTE: Once the old power scaling options (1/2, 1/4, 1/8) are deprecated, the
-# axis models here can be simplified.
-class AxisScale(ConfigBaseModel):
-    """Basic configuration for a plot axis."""
-
-    scale: Optional[ScaleEnum] = Field(
-        ScaleEnum.LINEAR,
-        description="""Defines the axis scaling. Defaults to linear scaling.""",
-    )
-
-
-class AxisQuantity(ConfigBaseModel):
-    """Configuration for a plot axis."""
-
-    title: Optional[str] = Field(description="""Custom title to show for the axis.""")
-    unit: Optional[str] = Field(
-        description="""Custom unit used for displaying the values."""
-    )
-    quantity: str = Field(
-        description="""
-        Path of the targeted quantity. Note that you can most of the features
-        JMESPath syntax here to further specify a selection of values. This
-        becomes especially useful when dealing with repeated sections or
-        statistical values.
-        """
-    )
-
-
-class Axis(AxisScale, AxisQuantity):
-    """Configuration for a plot axis with limited scaling options."""
-
-
 class AxisLimitedScale(AxisQuantity):
     """Configuration for a plot axis with limited scaling options."""
 
@@ -542,91 +931,56 @@ class Widget(ConfigBaseModel):
     )
 
 
-class WidgetTerms(Widget):
+class WidgetTerms(Widget, TermsBase):
     """Terms widget configuration."""
 
     type: Literal['terms'] = Field(
-        'terms', description='Set as `terms` to get this widget type.'
+        description='Set as `terms` to get this type.',
     )
-    quantity: str = Field(description='Targeted quantity.')
-    scale: ScaleEnum = Field(description='Statistics scaling.')
-    showinput: bool = Field(True, description='Whether to show text input field.')
 
 
-class WidgetHistogram(Widget):
+class WidgetHistogram(Widget, HistogramBase):
     """Histogram widget configuration."""
 
     type: Literal['histogram'] = Field(
-        'histogram', description='Set as `histogram` to get this widget type.'
-    )
-    quantity: Optional[str] = Field(
-        description='Targeted quantity. Note that this field is deprecated and `x` should be used instead.'
-    )
-    x: Union[Axis, str] = Field(
-        description='Configures the information source and display options for the x-axis.'
-    )
-    y: Union[AxisScale, str] = Field(
-        description='Configures the information source and display options for the y-axis.'
-    )
-    scale: Optional[ScaleEnum] = Field(
-        ScaleEnum.LINEAR, description='Statistics scaling.'
+        description='Set as `histogram` to get this type.',
     )
-    autorange: bool = Field(
-        True,
-        description='Whether to automatically set the range according to the data limits.',
-    )
-    showinput: bool = Field(
-        True,
-        description='Whether to show input text fields for minimum and maximum value.',
+
+
+class WidgetPeriodicTable(Widget, PeriodicTableBase):
+    """Periodic table widget configuration."""
+
+    type: Literal['periodic_table'] = Field(
+        description='Set as `periodic_table` to get this type.',
     )
-    nbins: int = Field(
-        description="""
-        Maximum number of histogram bins. Notice that the actual number of bins
-        may be smaller if there are fewer data items available.
-        """
+
+
+class WidgetPeriodicTableDeprecated(WidgetPeriodicTable):
+    """Deprecated copy of WidgetPeriodicTable with a misspelled type."""
+
+    type: Literal['periodictable'] = Field(  # type: ignore[assignment]
+        description='Set as `periodictable` to get this widget type.'
     )
 
     @root_validator(pre=True)
     def _validate(cls, values):
-        """Ensures backwards compatibility for quantity and scale."""
-        # X-axis
-        x = values.get('x', {})
-        if isinstance(x, str):
-            x = {'quantity': x}
-        if isinstance(x, dict):
-            quantity = values.get('quantity')
-            if quantity and not x.get('quantity'):
-                x['quantity'] = quantity
-                del values['quantity']
-            values['x'] = x
+        values['type'] = 'periodictable'
 
-        # Y-axis
-        y = values.get('y', {})
-        if isinstance(y, dict):
-            scale = values.get('scale')
-            if scale:
-                y['scale'] = scale
-                del values['scale']
-            values['y'] = y
+        # Backwards compatibility for quantity.
+        quantity = values.get('quantity')
+        search_quantity = values.get('search_quantity')
+        if quantity is not None and search_quantity is None:
+            values['search_quantity'] = quantity
+            del values['quantity']
 
         return values
 
 
-class WidgetPeriodicTable(Widget):
-    """Periodic table widget configuration."""
-
-    type: Literal['periodictable'] = Field(
-        'periodictable', description='Set as `periodictable` to get this widget type.'
-    )
-    quantity: str = Field(description='Targeted quantity.')
-    scale: ScaleEnum = Field(description='Statistics scaling.')
-
-
 class WidgetScatterPlot(Widget):
     """Scatter plot widget configuration."""
 
-    type: Literal['scatterplot'] = Field(
-        'scatterplot', description='Set as `scatterplot` to get this widget type.'
+    type: Literal['scatter_plot'] = Field(
+        description='Set as `scatter_plot` to get this widget type.'
     )
     x: Union[AxisLimitedScale, str] = Field(
         description='Configures the information source and display options for the x-axis.'
@@ -647,7 +1001,7 @@ class WidgetScatterPlot(Widget):
         1000,
         description="""
         Maximum number of entries to fetch. Notice that the actual number may be
-        more of less, depending on how many entries exist and how many of the
+        more or less, depending on how many entries exist and how many of the
         requested values each entry contains.
         """,
     )
@@ -658,24 +1012,50 @@ class WidgetScatterPlot(Widget):
 
     @root_validator(pre=True)
     def _validate(cls, values):
-        """Ensures backwards compatibility of x, y, and color."""
+        values['type'] = 'scatter_plot'
+
+        # color backwards compatibility
         color = values.get('color')
         if color is not None:
-            values['markers'] = {'color': {'quantity': color}}
+            values['markers'] = {'color': {'search_quantity': color}}
             del values['color']
+
+        # x backwards compatibility
         x = values.get('x')
         if isinstance(x, str):
-            values['x'] = {'quantity': x}
+            values['x'] = {'search_quantity': x}
+
+        # y backwards compatibility
         y = values.get('y')
         if isinstance(y, str):
-            values['y'] = {'quantity': y}
+            values['y'] = {'search_quantity': y}
+        return values
+
+
+class WidgetScatterPlotDeprecated(WidgetScatterPlot):
+    """Deprecated copy of WidgetScatterPlot with a misspelled type."""
+
+    type: Literal['scatterplot'] = Field(  # type: ignore[assignment]
+        description='Set as `scatterplot` to get this widget type.'
+    )
+
+    @root_validator(pre=True)
+    def _validate(cls, values):
+        values['type'] = 'scatterplot'
         return values
 
 
 # The 'discriminated union' feature of Pydantic is used here:
 # https://docs.pydantic.dev/usage/types/#discriminated-unions-aka-tagged-unions
 WidgetAnnotated = Annotated[
-    Union[WidgetTerms, WidgetHistogram, WidgetScatterPlot, WidgetPeriodicTable],
+    Union[
+        WidgetTerms,
+        WidgetHistogram,
+        WidgetScatterPlot,
+        WidgetScatterPlotDeprecated,
+        WidgetPeriodicTable,
+        WidgetPeriodicTableDeprecated,
+    ],
     Field(discriminator='type'),
 ]
 
@@ -685,7 +1065,7 @@ class Dashboard(ConfigBaseModel):
 
     widgets: List[WidgetAnnotated] = Field(
         description='List of widgets contained in the dashboard.'
-    )  # type: ignore
+    )
 
 
 class ResourceEnum(str, Enum):
@@ -723,12 +1103,18 @@ class App(ConfigBaseModel):
         ),
         description='Controls the display of entry rows in the results table.',
     )
-    filter_menus: FilterMenus = Field(
-        description='Filter menus displayed on the left side of the screen.'
+    menu: Optional[Menu] = Field(
+        description='Filter menu displayed on the left side of the screen.'
+    )
+    filter_menus: Optional[FilterMenus] = Field(
+        deprecated='The "filter_menus" field is deprecated, use "menu" instead.'
     )
     filters: Optional[Filters] = Field(
-        Filters(exclude=['mainfile', 'entry_name', 'combine']),
-        description='Controls the filters that are available in this app.',
+        deprecated='The "filters" field is deprecated, use "search_quantities" instead.'
+    )
+    search_quantities: Optional[SearchQuantities] = Field(
+        SearchQuantities(exclude=['mainfile', 'entry_name', 'combine']),
+        description='Controls the quantities that are available for search in this app.',
     )
     dashboard: Optional[Dashboard] = Field(description='Default dashboard layout.')
     filters_locked: Optional[dict] = Field(
@@ -764,6 +1150,672 @@ class App(ConfigBaseModel):
                     new_columns.append(column)
             values['columns'] = new_columns
 
+        # Backwards compatibility for Filters
+        filters = values.get('filters')
+        if filters and not values.get('search_quantities'):
+            values['search_quantities'] = filters
+
+        # Backwards compatibility for FilterMenus
+        filter_menus = values.get('filter_menus')
+        if isinstance(filter_menus, FilterMenus):
+            filter_menus = filter_menus.dict()
+        options = filter_menus.get('options') if filter_menus else None
+        menus = values.get('menus')
+        if options and not menus:
+            items = []
+            for key, value in options.items():
+                menu = {
+                    'material': Menu(),
+                    'elements': Menu(
+                        items=[
+                            MenuItemPeriodicTable(
+                                search_quantity='results.material.elements',
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.material.chemical_formula_hill',
+                                width=6,
+                                options=0,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.material.chemical_formula_iupac',
+                                width=6,
+                                options=0,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.material.chemical_formula_reduced',
+                                width=6,
+                                options=0,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.material.chemical_formula_anonymous',
+                                width=6,
+                                options=0,
+                            ),
+                            MenuItemHistogram(
+                                x='results.material.n_elements',
+                            ),
+                        ]
+                    ),
+                    'structure': Menu(
+                        items=[
+                            MenuItemTerms(
+                                search_quantity='results.material.structural_type',
+                                show_input=False,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.material.symmetry.bravais_lattice',
+                                n_columns=2,
+                                show_input=False,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.material.symmetry.crystal_system',
+                                n_columns=2,
+                                show_input=False,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.material.symmetry.space_group_symbol',
+                                options=0,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.material.symmetry.structure_name',
+                                options=5,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.material.symmetry.strukturbericht_designation',
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.material.symmetry.point_group',
+                                options=0,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.material.symmetry.hall_symbol',
+                                options=0,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.material.symmetry.prototype_aflow_id',
+                                options=0,
+                            ),
+                        ]
+                    ),
+                    'method': Menu(
+                        items=[
+                            MenuItemTerms(
+                                search_quantity='results.method.simulation.program_name',
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.method.simulation.program_version',
+                                options=0,
+                            ),
+                        ]
+                    ),
+                    'precision': Menu(
+                        items=[
+                            MenuItemHistogram(
+                                x='results.method.simulation.precision.k_line_density',
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.method.simulation.precision.native_tier',
+                                options=0,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.method.simulation.precision.basis_set',
+                                options=5,
+                            ),
+                            MenuItemHistogram(
+                                x=Axis(
+                                    search_quantity='results.method.simulation.precision.planewave_cutoff',
+                                )
+                            ),
+                            MenuItemHistogram(
+                                x='results.method.simulation.precision.apw_cutoff',
+                            ),
+                        ]
+                    ),
+                    'dft': Menu(
+                        items=[
+                            MenuItemTerms(
+                                search_quantity='results.method.method_name',
+                                show_header=False,
+                                show_input=False,
+                                show_statistics=False,
+                                options={
+                                    'DFT': MenuItemOption(label='Search DFT entries')
+                                },
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.method.simulation.dft.xc_functional_type',
+                                show_input=False,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.method.simulation.dft.xc_functional_names',
+                            ),
+                            MenuItemHistogram(
+                                x='results.method.simulation.dft.exact_exchange_mixing_factor',
+                            ),
+                            MenuItemHistogram(
+                                x='results.method.simulation.dft.hubbard_kanamori_model.u_effective',
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.method.simulation.dft.core_electron_treatment',
+                                show_input=False,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.method.simulation.dft.relativity_method',
+                                show_input=False,
+                            ),
+                        ]
+                    ),
+                    'tb': Menu(
+                        items=[
+                            MenuItemTerms(
+                                search_quantity='results.method.method_name',
+                                show_header=False,
+                                show_input=False,
+                                show_statistics=False,
+                                options={
+                                    'TB': MenuItemOption(label='Search TB entries')
+                                },
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.method.simulation.tb.type',
+                                show_input=False,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.method.simulation.tb.localization_type',
+                                show_input=False,
+                            ),
+                        ]
+                    ),
+                    'gw': Menu(
+                        items=[
+                            MenuItemTerms(
+                                search_quantity='results.method.method_name',
+                                show_header=False,
+                                show_input=False,
+                                show_statistics=False,
+                                options={
+                                    'GW': MenuItemOption(label='Search GW entries')
+                                },
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.method.simulation.gw.type',
+                                show_input=False,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.method.simulation.gw.starting_point_type',
+                                show_input=False,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.method.simulation.gw.basis_set_type',
+                                show_input=False,
+                            ),
+                        ]
+                    ),
+                    'bse': Menu(
+                        items=[
+                            MenuItemTerms(
+                                search_quantity='results.method.method_name',
+                                show_header=False,
+                                show_input=False,
+                                show_statistics=False,
+                                options={
+                                    'BSE': MenuItemOption(label='Search BSE entries')
+                                },
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.method.simulation.bse.type',
+                                show_input=False,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.method.simulation.bse.solver',
+                                show_input=False,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.method.simulation.bse.starting_point_type',
+                                show_input=False,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.method.simulation.bse.starting_point_type',
+                                show_input=False,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.method.simulation.bse.basis_set_type',
+                                show_input=False,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.method.simulation.bse.gw_type',
+                                show_input=False,
+                            ),
+                        ]
+                    ),
+                    'dmft': Menu(
+                        items=[
+                            MenuItemTerms(
+                                search_quantity='results.method.method_name',
+                                show_header=False,
+                                show_input=False,
+                                show_statistics=False,
+                                options={
+                                    'DMFT': MenuItemOption(label='Search DMFT entries')
+                                },
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.method.simulation.dmft.impurity_solver_type',
+                                n_columns=2,
+                                show_input=False,
+                            ),
+                            MenuItemHistogram(
+                                x='results.method.simulation.dmft.inverse_temperature',
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.method.simulation.dmft.magnetic_state',
+                                show_input=False,
+                            ),
+                            MenuItemHistogram(
+                                x='results.method.simulation.dmft.u',
+                            ),
+                            MenuItemHistogram(
+                                x='results.method.simulation.dmft.jh',
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.method.simulation.dmft.analytical_continuation',
+                                show_input=False,
+                            ),
+                        ]
+                    ),
+                    'eels': Menu(
+                        items=[
+                            MenuItemTerms(
+                                search_quantity='results.method.method_name',
+                                show_header=False,
+                                show_input=False,
+                                show_statistics=False,
+                                options={
+                                    'EELS': MenuItemOption(label='Search EELS entries')
+                                },
+                            ),
+                            MenuItemNestedObject(
+                                path='results.properties.spectroscopic.spectra.provenance.eels',
+                                items=[
+                                    MenuItemTerms(
+                                        search_quantity='results.properties.spectroscopic.spectra.provenance.eels.detector_type'
+                                    ),
+                                    MenuItemHistogram(
+                                        x='results.properties.spectroscopic.spectra.provenance.eels.resolution',
+                                    ),
+                                    MenuItemHistogram(
+                                        x='results.properties.spectroscopic.spectra.provenance.eels.min_energy',
+                                    ),
+                                    MenuItemHistogram(
+                                        x='results.properties.spectroscopic.spectra.provenance.eels.max_energy',
+                                    ),
+                                ],
+                            ),
+                        ]
+                    ),
+                    'workflow': Menu(),
+                    'molecular_dynamics': Menu(
+                        items=[
+                            MenuItemNestedObject(
+                                path='results.properties.thermodynamic.trajectory',
+                                items=[
+                                    MenuItemTerms(
+                                        search_quantity='results.properties.thermodynamic.trajectory.available_properties',
+                                        show_input=False,
+                                        options=4,
+                                    ),
+                                    MenuItemTerms(
+                                        search_quantity='results.properties.thermodynamic.trajectory.provenance.molecular_dynamics.ensemble_type',
+                                        show_input=False,
+                                        options=2,
+                                    ),
+                                    MenuItemHistogram(
+                                        x='results.properties.thermodynamic.trajectory.provenance.molecular_dynamics.time_step',
+                                    ),
+                                ],
+                            ),
+                        ]
+                    ),
+                    'geometry_optimization': Menu(
+                        items=[
+                            MenuItemTerms(
+                                search_quantity='results.properties.available_properties',
+                                show_header=False,
+                                show_input=False,
+                                show_statistics=False,
+                                options={
+                                    'geometry_optimization': MenuItemOption(
+                                        label='Search geometry optimization entries'
+                                    )
+                                },
+                            ),
+                            MenuItemNestedObject(
+                                path='results.properties.geometry_optimization',
+                                items=[
+                                    MenuItemHistogram(
+                                        x='results.properties.geometry_optimization.final_energy_difference',
+                                    ),
+                                    MenuItemHistogram(
+                                        x='results.properties.geometry_optimization.final_force_maximum',
+                                    ),
+                                    MenuItemHistogram(
+                                        x='results.properties.geometry_optimization.final_displacement_maximum',
+                                    ),
+                                ],
+                            ),
+                        ]
+                    ),
+                    'properties': Menu(),
+                    'electronic': Menu(
+                        items=[
+                            MenuItemTerms(
+                                search_quantity='electronic_properties',
+                                show_input=False,
+                            ),
+                            MenuItemNestedObject(
+                                path='results.properties.electronic.band_structure_electronic.band_gap',
+                                items=[
+                                    MenuItemTerms(
+                                        search_quantity='results.properties.electronic.band_structure_electronic.band_gap.type',
+                                        options=2,
+                                        show_input=False,
+                                    ),
+                                    MenuItemHistogram(
+                                        x='results.properties.electronic.band_structure_electronic.band_gap.value',
+                                    ),
+                                ],
+                            ),
+                            MenuItemNestedObject(
+                                path='results.properties.electronic.band_structure_electronic',
+                                items=[
+                                    MenuItemTerms(
+                                        search_quantity='results.properties.electronic.band_structure_electronic.spin_polarized',
+                                        show_input=False,
+                                    ),
+                                ],
+                            ),
+                            MenuItemNestedObject(
+                                path='results.properties.electronic.dos_electronic',
+                                items=[
+                                    MenuItemTerms(
+                                        search_quantity='results.properties.electronic.dos_electronic.spin_polarized',
+                                        show_input=False,
+                                    ),
+                                ],
+                            ),
+                        ]
+                    ),
+                    'vibrational': Menu(
+                        items=[
+                            MenuItemTerms(
+                                search_quantity='vibrational_properties',
+                                show_input=False,
+                            ),
+                        ]
+                    ),
+                    'mechanical': Menu(
+                        items=[
+                            MenuItemTerms(
+                                search_quantity='mechanical_properties',
+                                show_input=False,
+                            ),
+                            MenuItemNestedObject(
+                                path='results.properties.mechanical.bulk_modulus',
+                                items=[
+                                    MenuItemTerms(
+                                        search_quantity='results.properties.mechanical.bulk_modulus.type',
+                                    ),
+                                    MenuItemHistogram(
+                                        x='results.properties.mechanical.bulk_modulus.value',
+                                    ),
+                                ],
+                            ),
+                            MenuItemNestedObject(
+                                path='results.properties.mechanical.shear_modulus',
+                                items=[
+                                    MenuItemTerms(
+                                        search_quantity='results.properties.mechanical.shear_modulus.type',
+                                        show_input=False,
+                                    ),
+                                    MenuItemHistogram(
+                                        x='results.properties.mechanical.shear_modulus.value',
+                                    ),
+                                ],
+                            ),
+                            MenuItemNestedObject(
+                                path='results.properties.mechanical.energy_volume_curve',
+                                items=[
+                                    MenuItemTerms(
+                                        search_quantity='results.properties.mechanical.energy_volume_curve.type',
+                                        options=5,
+                                    ),
+                                ],
+                            ),
+                        ]
+                    ),
+                    'usecases': Menu(),
+                    'solarcell': Menu(
+                        items=[
+                            MenuItemHistogram(
+                                x='results.properties.optoelectronic.solar_cell.efficiency',
+                            ),
+                            MenuItemHistogram(
+                                x='results.properties.optoelectronic.solar_cell.fill_factor',
+                            ),
+                            MenuItemHistogram(
+                                x='results.properties.optoelectronic.solar_cell.open_circuit_voltage',
+                            ),
+                            MenuItemHistogram(
+                                x='results.properties.optoelectronic.solar_cell.short_circuit_current_density',
+                            ),
+                            MenuItemHistogram(
+                                x='results.properties.optoelectronic.solar_cell.illumination_intensity',
+                            ),
+                            MenuItemHistogram(
+                                x='results.properties.optoelectronic.solar_cell.device_area',
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.properties.optoelectronic.solar_cell.device_architecture',
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.properties.optoelectronic.solar_cell.device_stack',
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.properties.optoelectronic.solar_cell.absorber',
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.properties.optoelectronic.solar_cell.absorber_fabrication',
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.properties.optoelectronic.solar_cell.electron_transport_layer',
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.properties.optoelectronic.solar_cell.hole_transport_layer',
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.properties.optoelectronic.solar_cell.substrate',
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.properties.optoelectronic.solar_cell.back_contact',
+                            ),
+                        ]
+                    ),
+                    'heterogeneouscatalyst': Menu(
+                        items=[
+                            MenuItemTerms(
+                                search_quantity='results.properties.catalytic.reaction.name',
+                            ),
+                            MenuItemNestedObject(
+                                path='results.properties.catalytic.reaction.reactants',
+                                items=[
+                                    MenuItemTerms(
+                                        search_quantity='results.properties.catalytic.reaction.reactants.name',
+                                    ),
+                                    MenuItemHistogram(
+                                        x='results.properties.catalytic.reaction.reactants.conversion',
+                                    ),
+                                    MenuItemHistogram(
+                                        x='results.properties.catalytic.reaction.reactants.gas_concentration_in',
+                                    ),
+                                    MenuItemHistogram(
+                                        x='results.properties.catalytic.reaction.reactants.gas_concentration_out',
+                                    ),
+                                ],
+                            ),
+                            MenuItemNestedObject(
+                                path='results.properties.catalytic.reaction.products',
+                                items=[
+                                    MenuItemTerms(
+                                        search_quantity='results.properties.catalytic.reaction.products.name',
+                                    ),
+                                    MenuItemHistogram(
+                                        x='results.properties.catalytic.reaction.products.selectivity',
+                                    ),
+                                    MenuItemHistogram(
+                                        x='results.properties.catalytic.reaction.products.gas_concentration_out',
+                                    ),
+                                ],
+                            ),
+                            MenuItemHistogram(
+                                x='results.properties.catalytic.reaction.reaction_conditions.temperature',
+                            ),
+                            MenuItemNestedObject(
+                                path='results.properties.catalytic.catalyst',
+                                items=[
+                                    MenuItemTerms(
+                                        search_quantity='results.properties.catalytic.catalyst.catalyst_type',
+                                    ),
+                                    MenuItemTerms(
+                                        search_quantity='results.properties.catalytic.catalyst.preparation_method',
+                                    ),
+                                    MenuItemTerms(
+                                        search_quantity='results.properties.catalytic.catalyst.catalyst_name',
+                                    ),
+                                    MenuItemTerms(
+                                        search_quantity='results.properties.catalytic.catalyst.characterization_methods',
+                                    ),
+                                    MenuItemHistogram(
+                                        x='results.properties.catalytic.catalyst.surface_area',
+                                    ),
+                                ],
+                            ),
+                        ]
+                    ),
+                    'author': Menu(
+                        items=[
+                            MenuItemTerms(
+                                search_quantity='authors.name',
+                                options=0,
+                            ),
+                            MenuItemHistogram(
+                                x='upload_create_time',
+                            ),
+                            MenuItemTerms(
+                                search_quantity='external_db',
+                                options=5,
+                                show_input=False,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='datasets.dataset_name',
+                            ),
+                            MenuItemTerms(
+                                search_quantity='datasets.doi',
+                                options=0,
+                            ),
+                        ]
+                    ),
+                    'metadata': Menu(
+                        items=[
+                            MenuItemVisibility(),
+                            MenuItemTerms(
+                                search_quantity='entry_id',
+                                options=0,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='upload_id',
+                                options=0,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='upload_name',
+                                options=0,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.material.material_id',
+                                options=0,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='datasets.dataset_id',
+                                options=0,
+                            ),
+                            MenuItemDefinitions(),
+                        ]
+                    ),
+                    'optimade': Menu(items=[MenuItemOptimade()]),
+                    'eln': Menu(
+                        items=[
+                            MenuItemTerms(
+                                search_quantity='results.eln.sections',
+                                show_input=False,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.eln.tags',
+                                show_input=False,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.eln.methods',
+                                show_input=False,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.eln.instruments',
+                                show_input=False,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.eln.names',
+                                options=0,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.eln.descriptions',
+                                options=0,
+                            ),
+                            MenuItemTerms(
+                                search_quantity='results.eln.lab_ids',
+                                options=0,
+                            ),
+                        ]
+                    ),
+                    'custom_quantities': Menu(items=[MenuItemCustomQuantities()]),
+                    'combine': MenuItemTerms(
+                        search_quantity='combine',
+                        options={
+                            True: MenuItemOption(
+                                label='Combine results from several entries',
+                                description='If selected, your filters may be matched from several entries that contain the same material. When unchecked, the material has to have a single entry that matches all your filters.',
+                            )
+                        },
+                        show_header=False,
+                        show_input=False,
+                        show_statistics=False,
+                    ),
+                }.get(key)
+                if not menu:
+                    continue
+                size = value.get('size')
+                new_size = {
+                    FilterMenuSizeEnum.S: MenuSizeEnum.MD,
+                    FilterMenuSizeEnum.M: MenuSizeEnum.LG,
+                    FilterMenuSizeEnum.L: MenuSizeEnum.XL,
+                    FilterMenuSizeEnum.XL: MenuSizeEnum.XXL,
+                    None: MenuSizeEnum.MD,
+                }.get(size)
+                if isinstance(menu, Menu):
+                    menu.title = value.get('label')
+                    if new_size:
+                        menu.size = new_size
+                    menu.indentation = value.get('level')
+                items.append(menu)
+            del values['filter_menus']
+            values['menu'] = Menu(title='Filters', size=MenuSizeEnum.SM, items=items)
+
         return values
 
 
diff --git a/nomad/datamodel/results.py b/nomad/datamodel/results.py
index 51e551cef6..71e28f9751 100644
--- a/nomad/datamodel/results.py
+++ b/nomad/datamodel/results.py
@@ -1994,7 +1994,7 @@ class DMFT(MSection):
             a_elasticsearch=[Elasticsearch(material_entry_type)]
         )
     analytical_continuation = Quantity(
-        type=MEnum('Pade', 'MaxEnt', 'SVD', ''),
+        type=MEnum('Pade', 'MaxEnt', 'SVD', 'Stochastic'),
         shape=[],
         description="""
         Analytical continuation used to continuate the imaginary space Green's functions into
-- 
GitLab