Index: src/org/openstreetmap/josm/data/preferences/sources/ExtendedSourceEntry.java
===================================================================
--- src/org/openstreetmap/josm/data/preferences/sources/ExtendedSourceEntry.java	(revision 17544)
+++ src/org/openstreetmap/josm/data/preferences/sources/ExtendedSourceEntry.java	(working copy)
@@ -49,7 +49,7 @@
     }
 
     private static void appendRow(StringBuilder s, String th, String td) {
-        s.append("<tr><th>").append(th).append("</th><td>").append(Utils.escapeReservedCharactersHTML(td)).append("</td</tr>");
+        s.append("<tr><th>").append(th).append("</th><td>").append(Utils.escapeReservedCharactersHTML(td)).append("</td></tr>");
     }
 
     /**
Index: src/org/openstreetmap/josm/gui/preferences/DefaultTabPreferenceSetting.java
===================================================================
--- src/org/openstreetmap/josm/gui/preferences/DefaultTabPreferenceSetting.java	(revision 17544)
+++ src/org/openstreetmap/josm/gui/preferences/DefaultTabPreferenceSetting.java	(working copy)
@@ -48,7 +48,7 @@
         this.tabpane = tabpane;
         this.subSettingMap = tabpane != null ? new HashMap<>() : null;
         if (tabpane != null) {
-            tabpane.addMouseWheelListener(new PreferenceTabbedPane.WheelListener(tabpane));
+            tabpane.addMouseWheelListener(new PreferenceTabbedPane.MouseAndWheelListener(tabpane));
         }
     }
 
Index: src/org/openstreetmap/josm/gui/preferences/PreferenceTabbedPane.java
===================================================================
--- src/org/openstreetmap/josm/gui/preferences/PreferenceTabbedPane.java	(revision 17544)
+++ src/org/openstreetmap/josm/gui/preferences/PreferenceTabbedPane.java	(working copy)
@@ -10,6 +10,8 @@
 import java.awt.FontMetrics;
 import java.awt.GridBagConstraints;
 import java.awt.GridBagLayout;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
 import java.awt.event.MouseWheelEvent;
 import java.awt.event.MouseWheelListener;
 import java.util.ArrayList;
@@ -60,6 +62,8 @@
 import org.openstreetmap.josm.gui.preferences.plugin.PluginPreference;
 import org.openstreetmap.josm.gui.preferences.projection.ProjectionPreference;
 import org.openstreetmap.josm.gui.preferences.remotecontrol.RemoteControlPreference;
+import org.openstreetmap.josm.gui.preferences.search.SearchPanel;
+import org.openstreetmap.josm.gui.preferences.search.SearchTextField;
 import org.openstreetmap.josm.gui.preferences.server.ProxyPreference;
 import org.openstreetmap.josm.gui.preferences.server.ServerAccessPreference;
 import org.openstreetmap.josm.gui.preferences.shortcut.ShortcutPreference;
@@ -204,7 +208,7 @@
         boolean validatePreferences();
     }
 
-    private interface PreferenceTab {
+    public interface PreferenceTab {
         TabPreferenceSetting getTabPreferenceSetting();
 
         Component getComponent();
@@ -273,6 +277,9 @@
         }
     }
 
+    private final SearchPanel searchPanel = new SearchPanel(this);
+    private final SearchTextField searchTextField = new SearchTextField(searchPanel);
+
     // all created tabs
     private final transient List<PreferenceTab> tabs = new ArrayList<>();
     private static final Collection<PreferenceSettingFactory> SETTINGS_FACTORIES = new LinkedList<>();
@@ -463,7 +470,9 @@
      */
     public PreferenceTabbedPane() {
         super(SwingConstants.LEFT, JTabbedPane.SCROLL_TAB_LAYOUT);
-        super.addMouseWheelListener(new WheelListener(this));
+        MouseAndWheelListener l = new MouseAndWheelListener(this);
+        super.addMouseWheelListener(l);
+        super.addMouseListener(l);
         ExpertToggleAction.addExpertModeChangeListener(this);
     }
 
@@ -526,6 +535,9 @@
         if (clear) {
             removeAll();
         }
+
+        addTab(null, searchPanel);
+        setTabComponentAt(0, searchTextField);
         // Compute max tab length in pixels
         int maxWidth = computeMaxTabWidth();
         // Inspect each tab setting
@@ -557,6 +569,7 @@
                 Logging.debug("{0}: hiding empty {1}", getClass().getSimpleName(), tps);
             });
         }
+        searchTextField.adjustWidth();
         setSelectedIndex(-1);
     }
 
@@ -626,11 +639,11 @@
      * This mouse wheel listener reacts when a scroll is carried out over the
      * tab strip and scrolls one tab/down or up, selecting it immediately.
      */
-    static final class WheelListener implements MouseWheelListener {
+    static final class MouseAndWheelListener implements MouseWheelListener, MouseListener {
 
         final JTabbedPane tabbedPane;
 
-        WheelListener(JTabbedPane tabbedPane) {
+        MouseAndWheelListener(JTabbedPane tabbedPane) {
             this.tabbedPane = tabbedPane;
         }
 
@@ -646,6 +659,27 @@
 
             tabbedPane.setSelectedIndex(newTab);
         }
+
+        @Override
+        public void mouseClicked(MouseEvent e) {
+            tabbedPane.requestFocus();
+        }
+
+        @Override
+        public void mouseEntered(MouseEvent e) {
+        }
+
+        @Override
+        public void mouseExited(MouseEvent e) {
+        }
+
+        @Override
+        public void mousePressed(MouseEvent e) {
+        }
+
+        @Override
+        public void mouseReleased(MouseEvent e) {
+        }
     }
 
     @Override
@@ -653,38 +687,41 @@
         int index = getSelectedIndex();
         Component sel = getSelectedComponent();
         if (index > -1 && sel instanceof PreferenceTab) {
-            PreferenceTab tab = (PreferenceTab) sel;
-            TabPreferenceSetting preferenceSettings = tab.getTabPreferenceSetting();
-            if (!settingsInitialized.contains(preferenceSettings)) {
-                try {
-                    getModel().removeChangeListener(this);
-                    preferenceSettings.addGui(this);
-                    // Add GUI for sub preferences
-                    for (PreferenceSetting setting : settings) {
-                        if (setting instanceof SubPreferenceSetting) {
-                            addSubPreferenceSetting(preferenceSettings, (SubPreferenceSetting) setting);
-                        }
+            initializeTab(index, (PreferenceTab) sel, false);
+        }
+    }
+
+    public void initializeTab(int index, PreferenceTab tab, boolean silent) {
+        TabPreferenceSetting preferenceSettings = tab.getTabPreferenceSetting();
+        if (!settingsInitialized.contains(preferenceSettings)) {
+            try {
+                getModel().removeChangeListener(this);
+                preferenceSettings.addGui(this);
+                // Add GUI for sub preferences
+                for (PreferenceSetting setting : settings) {
+                    if (setting instanceof SubPreferenceSetting) {
+                        addSubPreferenceSetting(preferenceSettings, (SubPreferenceSetting) setting);
                     }
-                    Icon icon = getIconAt(index);
-                    remove(index);
-                    if (index <= insertGUITabsForSetting(icon, preferenceSettings, index, computeMaxTabWidth())) {
-                        setSelectedIndex(index);
-                    }
-                } catch (SecurityException ex) {
-                    Logging.error(ex);
-                } catch (RuntimeException ex) { // NOPMD
-                    // allow to change most settings even if e.g. a plugin fails
-                    BugReportExceptionHandler.handleException(ex);
-                } finally {
-                    settingsInitialized.add(preferenceSettings);
-                    getModel().addChangeListener(this);
                 }
+                Icon icon = getIconAt(index);
+                remove(index);
+                if (index <= insertGUITabsForSetting(icon, preferenceSettings, index, computeMaxTabWidth()) && !silent) {
+                    setSelectedIndex(index);
+                }
+            } catch (SecurityException ex) {
+                Logging.error(ex);
+            } catch (RuntimeException ex) { // NOPMD
+                // allow to change most settings even if e.g. a plugin fails
+                BugReportExceptionHandler.handleException(ex);
+            } finally {
+                settingsInitialized.add(preferenceSettings);
+                getModel().addChangeListener(this);
             }
-            Container ancestor = getTopLevelAncestor();
-            if (ancestor instanceof PreferenceDialog) {
-                ((PreferenceDialog) ancestor).setHelpContext(preferenceSettings.getHelpContext());
-            }
         }
+        Container ancestor = getTopLevelAncestor();
+        if (ancestor instanceof PreferenceDialog) {
+            ((PreferenceDialog) ancestor).setHelpContext(preferenceSettings.getHelpContext());
+        }
     }
 
     private void addSubPreferenceSetting(TabPreferenceSetting preferenceSettings, SubPreferenceSetting sps) {
Index: src/org/openstreetmap/josm/gui/preferences/advanced/AdvancedPreference.java
===================================================================
--- src/org/openstreetmap/josm/gui/preferences/advanced/AdvancedPreference.java	(revision 17544)
+++ src/org/openstreetmap/josm/gui/preferences/advanced/AdvancedPreference.java	(working copy)
@@ -52,6 +52,7 @@
 import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
 import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory;
 import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
+import org.openstreetmap.josm.gui.preferences.search.NotSearchablePanel;
 import org.openstreetmap.josm.gui.util.GuiHelper;
 import org.openstreetmap.josm.gui.widgets.AbstractFileChooser;
 import org.openstreetmap.josm.gui.widgets.JosmTextField;
@@ -164,8 +165,11 @@
 
     @Override
     public void addGui(final PreferenceTabbedPane gui) {
-        JPanel p = gui.createPreferenceTab(this);
+        JPanel panel = gui.createPreferenceTab(this);
 
+        NotSearchablePanel p = new NotSearchablePanel(new GridBagLayout());
+        panel.add(p, GBC.std().fill());
+
         final JPanel txtFilterPanel = new JPanel(new GridBagLayout());
         p.add(txtFilterPanel, GBC.eol().fill(GBC.HORIZONTAL));
         txtFilter = new JosmTextField();
Index: src/org/openstreetmap/josm/gui/preferences/search/ISearchableComponent.java
===================================================================
--- src/org/openstreetmap/josm/gui/preferences/search/ISearchableComponent.java	(nonexistent)
+++ src/org/openstreetmap/josm/gui/preferences/search/ISearchableComponent.java	(working copy)
@@ -0,0 +1,36 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.preferences.search;
+
+import java.util.List;
+
+/**
+ * Interface allowing components in the preferences to determine if and how they can be searched
+ * @author Bjoeni
+ */
+public interface ISearchableComponent {
+    /**
+     * @return whether the component can be searched<br><br>
+     * default: true
+     */
+    default boolean isSearchable() {
+        return true;
+    }
+
+    /**
+     * @return whether the children of this component should be traversed <br><br>
+     *
+     * default: same as {@link #isSearchable()} unless explicitly overridden
+     */
+    default boolean isChildrenSearchable() {
+        return isSearchable();
+    }
+
+    /**
+     * @return the {@link SearchItem}s that should be used. Ignored if {@link #isSearchable()} returns {@code false}.<br>
+     * Overrides the default {@link SearchTextFinder} if returning not {@code null} (including if an empty list is returned)<br><br>
+     * default: null
+     */
+    default List<SearchItem> getSearchItems() {
+        return null;
+    }
+}
Index: src/org/openstreetmap/josm/gui/preferences/search/NotSearchablePanel.java
===================================================================
--- src/org/openstreetmap/josm/gui/preferences/search/NotSearchablePanel.java	(nonexistent)
+++ src/org/openstreetmap/josm/gui/preferences/search/NotSearchablePanel.java	(working copy)
@@ -0,0 +1,56 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.preferences.search;
+
+import java.awt.LayoutManager;
+
+import javax.swing.JPanel;
+
+/**
+ * {@link JPanel} that disallows searching its contents
+ * @see ISearchableComponent
+ * @author Bjoeni
+ */
+public class NotSearchablePanel extends JPanel implements ISearchableComponent {
+
+    /**
+     * Create {@link JPanel} that disallows searching its contents
+     */
+    public NotSearchablePanel() {
+        super();
+    }
+
+    /**
+     * Create {@link JPanel} that disallows searching its contents
+     * @param layout
+     */
+    public NotSearchablePanel(LayoutManager layout) {
+        super(layout);
+    }
+
+    /**
+     * Create {@link JPanel} that disallows searching its contents
+     * @param isDoubleBuffered
+     */
+    public NotSearchablePanel(boolean isDoubleBuffered) {
+        super(isDoubleBuffered);
+    }
+
+    /**
+     * Create {@link JPanel} that disallows searching its contents
+     * @param layout
+     * @param isDoubleBuffered
+     */
+    public NotSearchablePanel(LayoutManager layout, boolean isDoubleBuffered) {
+        super(layout, isDoubleBuffered);
+    }
+
+    /**
+     * The component can not be searched
+     * @return false
+     */
+    @Override
+    public boolean isSearchable() {
+        return false;
+    }
+
+}
Index: src/org/openstreetmap/josm/gui/preferences/search/SearchIndex.java
===================================================================
--- src/org/openstreetmap/josm/gui/preferences/search/SearchIndex.java	(nonexistent)
+++ src/org/openstreetmap/josm/gui/preferences/search/SearchIndex.java	(working copy)
@@ -0,0 +1,169 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.preferences.search;
+
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.LayoutManager;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Stack;
+
+import javax.swing.JComponent;
+import javax.swing.JSeparator;
+
+import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
+import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane.PreferenceTab;
+
+/**
+ * Contains all {@link SearchItem}s
+ * @author Bjoeni
+ */
+public class SearchIndex {
+    Stack<SearchItem> stack = new Stack<>();
+    public List<SearchItem> parents = new ArrayList<>();
+    PreferenceTabbedPane prefTabs;
+    GridBagConstraints lastConstraint;
+
+    public SearchIndex(PreferenceTabbedPane prefTabs) {
+        this.prefTabs = prefTabs;
+    }
+
+    void add(SearchItem item) {
+        if (stack.isEmpty()) {
+            item.level = 0;
+            parents.add(item);
+            stack.push(item);
+        } else {
+            SearchItem lastItem = stack.lastElement();
+            if (!lastItem.eol && lastItem.level == item.level) {
+                lastItem.eol = item.eol;
+                lastItem.addChild(item);
+            } else if (lastItem.level < item.level || (lastItem.level == item.level && lastItem.inset < item.inset)) {
+                stack.push(lastItem.addChild(item));
+            } else {
+                stack.pop();
+                add(item);
+            }
+        }
+    }
+
+    void addAll(List<SearchItem> items, boolean isEOL) {
+        if (items.size() > 0) {
+            items.get(items.size() - 1).eol = isEOL;
+        }
+        items.forEach(item -> add(item));
+    }
+
+    void insertEOL() {
+        if (!stack.isEmpty()) {
+            stack.lastElement().eol = true;
+        }
+    }
+
+    void insertSeparator() {
+        if (!stack.isEmpty()) {
+            stack.lastElement().inset = Integer.MAX_VALUE;
+        }
+    }
+
+    void insertNewPage() {
+        stack.clear();
+    }
+
+    public void build() {
+        for (int i = 0; i < prefTabs.getTabCount(); i++) {
+            Component c = prefTabs.getComponentAt(i);
+            if (c instanceof PreferenceTab) {
+                prefTabs.initializeTab(i, (PreferenceTab) c, true);
+                c = prefTabs.getComponentAt(i);
+            }
+            insertNewPage();
+            searchComponent(c, 1);
+        }
+    }
+
+    private boolean searchComponent(Component comp, int level) {
+
+        final Component c = comp;
+
+        boolean isEOL = true;
+        GridBagConstraints currentConstraint = null;
+
+        Container p = c.getParent();
+        if (p != null) {
+            LayoutManager layout = p.getLayout();
+            if (layout != null && layout instanceof GridBagLayout) {
+                GridBagLayout grid = (GridBagLayout) layout;
+
+                currentConstraint = grid.getConstraints(c);
+                isEOL = currentConstraint.gridwidth == GridBagConstraints.REMAINDER;
+            }
+        }
+
+        if (lastConstraint != null && currentConstraint != null
+                && (((lastConstraint.fill == GridBagConstraints.HORIZONTAL
+                        || lastConstraint.fill == GridBagConstraints.BOTH)
+                        && currentConstraint.fill != GridBagConstraints.HORIZONTAL
+                        && currentConstraint.fill != GridBagConstraints.BOTH)
+                        || lastConstraint.gridy != currentConstraint.gridy)) {
+            insertEOL();
+        }
+
+        lastConstraint = currentConstraint;
+        ISearchableComponent s = null;
+        if (c instanceof ISearchableComponent) {
+            s = (ISearchableComponent) c;
+        }
+
+        if (s == null || s.isSearchable()) {
+
+            List<SearchItem> items = null;
+            if (s != null) {
+                items = s.getSearchItems();
+            }
+            if (items == null) {
+                List<SearchItem> itm = new ArrayList<>();
+                SearchTextFinder.DEFAULT_SEARCH_TEXT_FINDERS.forEach(finder -> itm.addAll(finder.getSearchItems(c)));
+                items = itm;
+            }
+            if (items.size() == 0) {
+                if (isEOL) {
+                    insertEOL();
+                }
+                if (c instanceof JSeparator) {
+                    insertSeparator();
+                }
+
+            } else {
+                items.get(0).components.add(c);
+                if (c instanceof JComponent) {
+                    items.get(0).tooltip = ((JComponent) c).getToolTipText();
+                }
+
+                final int inset = currentConstraint == null ? 0 : currentConstraint.insets.left;
+                items.forEach(item -> {
+                    item.level = level;
+                    item.inset = inset;
+                });
+
+                addAll(items, isEOL);
+            }
+        }
+
+        if ((s == null || s.isChildrenSearchable()) && c instanceof Container) {
+            Container cont = (Container) c;
+            List<Component> components = Arrays.asList(cont.getComponents());
+            if (components.size() > 0) {
+                insertEOL();
+                for (Component component : components) {
+                    searchComponent(component, level + 1);
+                }
+            }
+        }
+        return isEOL;
+    }
+
+}
\ No newline at end of file
Index: src/org/openstreetmap/josm/gui/preferences/search/SearchItem.java
===================================================================
--- src/org/openstreetmap/josm/gui/preferences/search/SearchItem.java	(nonexistent)
+++ src/org/openstreetmap/josm/gui/preferences/search/SearchItem.java	(working copy)
@@ -0,0 +1,68 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.preferences.search;
+
+import java.awt.Component;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * Contains searchable items and their components
+ * @author Bjoeni
+ */
+public class SearchItem {
+    List<Component> components = new ArrayList<>();
+    String text;
+    String tooltip;
+    int level;
+    int inset = 0;
+    public boolean eol = true;
+    public List<SearchItem> children = new ArrayList<>();
+
+    public SearchItem() {
+    }
+
+    public SearchItem(String text) {
+        this.text = text;
+    }
+
+    public SearchItem(Component component, String text, String tooltip, boolean eol) {
+        this.components.add(component);
+        this.text = text;
+        this.tooltip = tooltip;
+        this.eol = eol;
+    }
+
+    public SearchItem(Component component, String text, String tooltip, int level, int inset) {
+        this.components.add(component);
+        this.text = text;
+        this.tooltip = tooltip;
+        this.level = level;
+        this.inset = inset;
+    }
+
+    public void merge(SearchItem item) {
+        this.components.addAll(item.components);
+        this.eol = this.eol || item.eol;
+    }
+
+    @Override
+    public String toString() {
+        return text + (tooltip == null ? "" : " (Tooltip: " + tooltip + ")") + " [" + level + "." + inset + "]";
+    }
+
+    public SearchItem addChild(SearchItem item) {
+        Optional<SearchItem> match = children.stream()
+                .filter(c -> Objects.equals(c.text, item.text) && c.level == item.level && c.inset == item.inset)
+                .findAny();
+
+        if (match.isPresent()) {
+            match.get().merge(item);
+            return match.get();
+        } else {
+            children.add(item);
+            return item;
+        }
+    }
+}
\ No newline at end of file
Index: src/org/openstreetmap/josm/gui/preferences/search/SearchPanel.java
===================================================================
--- src/org/openstreetmap/josm/gui/preferences/search/SearchPanel.java	(nonexistent)
+++ src/org/openstreetmap/josm/gui/preferences/search/SearchPanel.java	(working copy)
@@ -0,0 +1,73 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.preferences.search;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import javax.swing.JLabel;
+import javax.swing.JScrollPane;
+import javax.swing.filechooser.FileSystemView;
+
+import org.apache.commons.io.FileUtils;
+import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
+import org.openstreetmap.josm.tools.Logging;
+
+/**
+ * Panel displaying search results in the preferences
+ * @author Bjoeni
+ */
+public class SearchPanel extends JScrollPane implements ISearchableComponent {
+
+    private PreferenceTabbedPane tabs;
+    private SearchIndex searchIndex;
+    private JLabel lbl = new JLabel("search results here");
+
+
+    public SearchPanel(PreferenceTabbedPane tabs) {
+        this.tabs = tabs;
+        add(lbl);
+    }
+
+    public PreferenceTabbedPane getTabPane() {
+        return tabs;
+    }
+
+    public void search(String text) {
+        searchIndex = new SearchIndex(tabs);
+
+        searchIndex.build();
+        Logging.info("searched");
+        searchableSettings = new StringBuilder();
+        printSearchItems(searchIndex.parents, "");
+        try {
+            FileUtils.writeStringToFile(new File(FileSystemView.getFileSystemView().getHomeDirectory().getAbsolutePath()
+                    + "/searchableSettings.txt"), searchableSettings.toString());
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        lbl.setText(searchableSettings.toString());
+    }
+
+    StringBuilder searchableSettings;
+
+    private void printSearchItems(List<SearchItem> items, String indent) {
+        items.forEach(item -> {
+            searchableSettings.append("\n" + indent + item.toString().replaceAll("\n", "<br>"));
+            if (item.eol) {
+                searchableSettings.append("\n" + indent + "==");
+            }
+            if (item.children.size() > 0) {
+                searchableSettings.append("\n" + indent + ">>");
+                printSearchItems(item.children, indent + "  ");
+                searchableSettings.append("\n" + indent + "<<");
+            }
+        });
+    }
+
+    @Override
+    public boolean isSearchable() {
+        return false;
+    }
+
+}
Index: src/org/openstreetmap/josm/gui/preferences/search/SearchTextField.java
===================================================================
--- src/org/openstreetmap/josm/gui/preferences/search/SearchTextField.java	(nonexistent)
+++ src/org/openstreetmap/josm/gui/preferences/search/SearchTextField.java	(working copy)
@@ -0,0 +1,65 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.preferences.search;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Dimension;
+
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+
+import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
+import org.openstreetmap.josm.gui.widgets.JosmTextField;
+
+/**
+ * TextField for searching the preferences
+ * @author Bjoeni
+ */
+public class SearchTextField extends JosmTextField {
+    private SearchPanel panel;
+    private PreferenceTabbedPane tabs;
+
+    public SearchTextField(SearchPanel panel) {
+
+        this.panel = panel;
+        tabs = panel.getTabPane();
+        setHint(tr("Search..."));
+        getDocument().addDocumentListener(new DocumentListener() {
+
+            @Override
+            public void removeUpdate(DocumentEvent e) {
+                panel.getTabPane().setSelectedIndex(0);
+                panel.search(getTextContent());
+            }
+
+            @Override
+            public void insertUpdate(DocumentEvent e) {
+                panel.getTabPane().setSelectedIndex(0);
+                panel.search(getTextContent());
+
+            }
+
+            @Override
+            public void changedUpdate(DocumentEvent e) {
+            }
+        });
+    }
+
+    public void adjustWidth() {
+        int width = getPreferredSize().width;
+        for (int i = 0; i < tabs.getTabCount(); i++) {
+            width = Math.max(width, tabs.getBoundsAt(i).width);
+        }
+        setPreferredSize(new Dimension(width, getPreferredSize().height));
+    }
+
+    @Override
+    public String getText() {
+        return tr("Search");
+    }
+
+    public String getTextContent() {
+        return super.getText();
+    }
+
+}
Index: src/org/openstreetmap/josm/gui/preferences/search/SearchTextFinder.java
===================================================================
--- src/org/openstreetmap/josm/gui/preferences/search/SearchTextFinder.java	(nonexistent)
+++ src/org/openstreetmap/josm/gui/preferences/search/SearchTextFinder.java	(working copy)
@@ -0,0 +1,205 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.preferences.search;
+
+import java.awt.Component;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JRadioButton;
+import javax.swing.JTable;
+import javax.swing.table.TableModel;
+
+/**
+ * Class for obtaining the searchable properties of arbitrary components
+ * @param <T> type of the component
+ * @author Bjoeni
+ */
+public class SearchTextFinder<T extends Component> {
+    List<IComponentProperties<T>> properties = new ArrayList<>();
+
+    @FunctionalInterface
+    private interface IComponentProperties<U extends Component> {
+        Object getFrom(U component);
+
+        default List<SearchItem> getSearchItems(U component) {
+            Object obj = getFrom(component);
+
+            if (obj == null) {
+                return new ArrayList<>();
+            }
+
+            if (obj instanceof String) {
+                return Arrays.asList(new SearchItem((String) obj));
+            }
+
+            if (obj instanceof String[]) {
+                return Arrays.asList((String[]) obj).stream().map(SearchItem::new).collect(Collectors.toList());
+            }
+
+            if (obj instanceof SearchItem[]) {
+                return Arrays.asList((SearchItem[]) obj);
+            }
+
+            throw new IllegalArgumentException();
+        }
+    }
+
+    @FunctionalInterface
+    interface ComponentProperty<U extends Component> extends IComponentProperties<U> {
+        @Override
+        String getFrom(U component);
+    }
+
+    @FunctionalInterface
+    interface ComponentPropertyArray<U extends Component> extends IComponentProperties<U> {
+        @Override
+        String[] getFrom(U component);
+    }
+
+    @FunctionalInterface
+    interface ComponentPropertyItem<U extends Component> extends IComponentProperties<U> {
+        @Override
+        SearchItem[] getFrom(U component);
+    }
+
+    /**
+     * Instantiates {@link SearchTextFinder}
+     */
+    public SearchTextFinder() {
+    }
+
+    /**
+     * Instantiates {@link SearchTextFinder}
+     * @param prop Expression returning a searchable string for the given component, e.g. {@code JLabel::getText}.
+     * @see #add(ComponentProperty)
+     * @see #addArray(ComponentPropertyArray)
+     */
+    public SearchTextFinder(ComponentProperty<T> prop) {
+        properties.add(prop);
+    }
+
+    /**
+     * Add another property.
+     * The compiler can't deal with generic vararg parameters properly, so just use this function instead
+     * @param prop Expression returning a searchable string for the given component, e.g. {@code JLabel::getText}.
+     * @return this (for chaining)
+     */
+    public SearchTextFinder<T> add(ComponentProperty<T> prop) {
+        properties.add(prop);
+        return this;
+    }
+
+    /**
+     * Add a property returning a string array.
+     * The compiler can't deal with generic vararg parameters properly, so just use this function instead
+     * @param prop Expression returning an array of searchable strings for the given component
+     * @return this (for chaining)
+     */
+    public SearchTextFinder<T> addArray(ComponentPropertyArray<T> prop) {
+        properties.add(prop);
+        return this;
+    }
+
+    /**
+     * Add a property returning a string array.
+     * The compiler can't deal with generic vararg parameters properly, so just use this function instead
+     * @param prop Expression returning an array of searchable strings for the given component
+     * @return this (for chaining)
+     */
+    public SearchTextFinder<T> addItem(ComponentPropertyItem<T> prop) {
+        properties.add(prop);
+        return this;
+    }
+
+    /**
+     * Get the searchable texts for the given component
+     * @param c component
+     * @return {@code List<String>} or an empty list if it's not the right type.
+     */
+    public List<SearchItem> getSearchItems(Component c) {
+        List<SearchItem> ret = new ArrayList<>();
+
+        try {
+            @SuppressWarnings("unchecked")
+            T component = (T) c;
+            if (component != null) {
+                properties.forEach(property -> {
+                    List<SearchItem> items = property.getSearchItems(component);
+                    items.forEach(item -> {
+                        if (item.text != null && item.text.trim().length() > 0) {
+                            if (item.text.indexOf('<') != -1) {
+                                item.text = stripHtml(item.text);
+                            }
+                            if (item.text.indexOf(':') == item.text.length() - 1) {
+                                item.text = item.text.substring(0, item.text.length() - 1);
+                            }
+                            if (item.tooltip != null && item.tooltip.indexOf('<') != -1) {
+                                item.tooltip = stripHtml(item.tooltip);
+                            }
+                            ret.add(item);
+                        }
+                    });
+                });
+            }
+
+        } catch (ClassCastException ex) {
+            // can't use 'instanceof' here, because the type information of T will already be stripped away at runtime
+        }
+        return ret;
+    }
+
+    private String stripHtml(String text) {
+        return text
+                .replaceAll("<br\s*/?>", "\n")
+                .replaceAll("(<style>.*</style>|<[^<>]*>)", " ")
+                .trim()
+                .replaceAll(" +", " ");
+    }
+
+    public final static List<SearchTextFinder<?>> DEFAULT_SEARCH_TEXT_FINDERS = Collections.unmodifiableList(Arrays.asList(
+
+                    new SearchTextFinder<>(JLabel::getText),
+                    new SearchTextFinder<>(JRadioButton::getText),
+                    new SearchTextFinder<>(JCheckBox::getText),
+
+                    new SearchTextFinder<JTable>().addItem(table -> {
+                        List<SearchItem> lst = new ArrayList<>();
+                        TableModel tm = table.getModel();
+                        for (int row = 0; row < tm.getRowCount(); row++) {
+                            for (int col = 0; col < tm.getColumnCount(); col++) {
+                                Object obj = tm.getValueAt(row, col);
+                                Component renderer = table.getCellRenderer(row, col)
+                                        .getTableCellRendererComponent(table, obj, false, false, row, col);
+                                if (renderer instanceof JLabel) {
+                                    JLabel label = (JLabel) renderer;
+                                    boolean isLast = col == tm.getColumnCount() - 1;
+                                    lst.add(new SearchItem(label, label.getText(), label.getToolTipText(), isLast));
+                                }
+                            }
+                        }
+                        return lst.toArray(new SearchItem[0]);
+                    }),
+
+                    new SearchTextFinder<JComboBox<Object>>().addItem(combobox -> {
+                        List<SearchItem> lst = new ArrayList<>();
+                        int size = combobox.getItemCount();
+                        JList<Object> listStub = new JList<>();
+                        for (int i = 0; i < size; i++) {
+                            Component renderer = combobox.getRenderer().getListCellRendererComponent(listStub,
+                                    combobox.getItemAt(i), i, false, false);
+                            if (renderer instanceof JLabel) {
+                                JLabel label = (JLabel) renderer;
+                                lst.add(new SearchItem(renderer, label.getText(), label.getToolTipText(), false));
+                            }
+                        }
+                        return lst.toArray(new SearchItem[0]);
+                    })));
+
+}
\ No newline at end of file
Index: src/org/openstreetmap/josm/gui/preferences/search/package-info.java
===================================================================
--- src/org/openstreetmap/josm/gui/preferences/search/package-info.java	(nonexistent)
+++ src/org/openstreetmap/josm/gui/preferences/search/package-info.java	(working copy)
@@ -0,0 +1 @@
+package org.openstreetmap.josm.gui.preferences.search;
\ No newline at end of file
Index: src/org/openstreetmap/josm/gui/preferences/shortcut/PrefJPanel.java
===================================================================
--- src/org/openstreetmap/josm/gui/preferences/shortcut/PrefJPanel.java	(revision 17544)
+++ src/org/openstreetmap/josm/gui/preferences/shortcut/PrefJPanel.java	(working copy)
@@ -15,6 +15,7 @@
 import java.awt.event.KeyEvent;
 import java.awt.im.InputContext;
 import java.lang.reflect.Field;
+import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -39,6 +40,8 @@
 import javax.swing.table.TableColumnModel;
 
 import org.openstreetmap.josm.data.preferences.NamedColorProperty;
+import org.openstreetmap.josm.gui.preferences.search.SearchItem;
+import org.openstreetmap.josm.gui.preferences.search.ISearchableComponent;
 import org.openstreetmap.josm.gui.util.GuiHelper;
 import org.openstreetmap.josm.gui.util.TableHelper;
 import org.openstreetmap.josm.gui.widgets.FilterField;
@@ -50,7 +53,7 @@
 /**
  * This is the keyboard preferences content.
  */
-public class PrefJPanel extends JPanel {
+public class PrefJPanel extends JPanel implements ISearchableComponent {
 
     // table of shortcuts
     private final AbstractTableModel model;
@@ -363,4 +366,18 @@
             }
         }
     }
+
+    @Override
+    public boolean isChildrenSearchable() {
+        return false;
+    }
+
+    @Override
+    public List<SearchItem> getSearchItems() {
+        List<SearchItem> list = new ArrayList<>();
+        for (int row = 0; row < model.getRowCount(); row++) {
+            list.add(new SearchItem(model.getValueAt(row, 0).toString()));
+        }
+        return list;
+    }
 }
