diff --git a/web/config.json b/web/config.json
index 588c62f..f772808 100644
--- a/web/config.json
+++ b/web/config.json
@@ -5,7 +5,8 @@
         "type": "string",
         "default": "ESP32NMEA2K",
         "check": "checkSystemName",
-        "description": "system name, used for the access point and for services"
+        "description": "system name, used for the access point and for services",
+        "category":"system"
     },
     {
         "name":"talkerId",
@@ -13,7 +14,16 @@
         "type":"list",
         "default":"GP",
         "list":["AB","AD","AG","AP","AI","AN","AR","AS","AT","AX","BI","BN","CA","CD","CR","CS","CT","CV","CX","DF","DU","DP","EC","EI","EP","ER","FD","FE","FR","FS","GA","GB","GI","GL","GN","GP","GQ","HC","HE","HF","HN","HD","HS","II","IN","JA","JB","JC","JD","JE","JF","JG","JH","LC","NL","NV","RA","RB","RC","RI","SA","SC","SD","SG","SN","SS","TC","TI","UP","VD","VM","VW","VA","VS","VT","VR","WD","WI","WL","YX","ZA","ZC","ZQ","ZV"],
-        "description":"the talkerId used in generated NMEA0183 records"
+        "description":"the talkerId used in generated NMEA0183 records",
+        "category":"system"
+    },
+    {
+        "name": "stopApTime",
+        "type": "number",
+        "default": "0",
+        "check": "checkStopApTime",
+        "description": "stop the access point after that many minutes if not used",
+        "category":"system"
     },
     {
         "name": "usbBaud",
@@ -21,42 +31,48 @@
         "type": "list",
         "default": "115200",
         "description": "baud rate for the USB port",
-        "list": [1200,2400,4800,9600,14400,19200,28800,38400,57600,115200,230400,460800]
+        "list": [1200,2400,4800,9600,14400,19200,28800,38400,57600,115200,230400,460800],
+        "category":"usb port"
     },
     {
         "name": "sendUsb",
         "label": "NMEA to USB",
         "type": "boolean",
         "default": "true",
-        "description": "send out NMEA data on the USB port"
+        "description": "send out NMEA data on the USB port",
+        "category":"usb port"
     },
     {
         "name": "receiveUsb",
         "label": "NMEA from USB",
         "type": "boolean",
         "default": "true",
-        "description": "receive NMEA data on the USB port"
+        "description": "receive NMEA data on the USB port",
+        "category":"usb port"
     },
     {
         "name": "usbToN2k",
         "label": "USB to NMEA2000",
         "type": "boolean",
         "default": "true",
-        "description": "convert NMEA0183 from the USB port to NMEA2000"
+        "description": "convert NMEA0183 from the USB port to NMEA2000",
+        "category":"usb port"
     },
     {
         "name": "usbReadFilter",
         "label": "USB read Filter",
         "type": "filter",
         "default": "",
-        "description": "filter for NMEA0183 data when reading from USB\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB"
+        "description": "filter for NMEA0183 data when reading from USB\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
+        "category":"usb port"
     },
     {
         "name": "usbWriteFilter",
         "label": "USB write Filter",
         "type": "filter",
         "default": "",
-        "description": "filter for NMEA0183 data when writing to USB\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB"
+        "description": "filter for NMEA0183 data when writing to USB\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
+        "category":"usb port"
     },
     {
         "name": "serialDirection",
@@ -65,7 +81,8 @@
         "default": "receive",
         "list": ["send","receive","off"],
         "description": "use the serial port to send or receive data",
-        "capabilities":{"serialmode":["UNI"]}
+        "capabilities":{"serialmode":["UNI"]},
+        "category":"serial port"
     },
     {
         "name": "serialBaud",
@@ -74,7 +91,8 @@
         "default": "115200",
         "description": "baud rate for the serial port",
         "list": [1200,2400,4800,9600,14400,19200,28800,38400,57600,115200,230400,460800],
-        "capabilities":{"serialmode":["RX","TX","UNI","BI"]}
+        "capabilities":{"serialmode":["RX","TX","UNI","BI"]},
+        "category":"serial port"
     },
     {
         "name": "sendSerial",
@@ -82,7 +100,8 @@
         "type": "boolean",
         "default": "true",
         "description": "send out NMEA data on the serial port",
-        "capabilities":{"serialmode":["TX","BI"]}
+        "capabilities":{"serialmode":["TX","BI"]},
+        "category":"serial port"
     },
     {
         "name": "receiveSerial",
@@ -90,7 +109,8 @@
         "type": "boolean",
         "default": "true",
         "description": "receive NMEA data on the serial port",
-        "capabilities":{"serialmode":["RX","BI"]}
+        "capabilities":{"serialmode":["RX","BI"]},
+        "category":"serial port"
     },
     {
         "name": "serialToN2k",
@@ -98,7 +118,8 @@
         "type": "boolean",
         "default": "true",
         "description": "convert NMEA0183 from the serial port to NMEA2000",
-        "capabilities":{"serialmode":["RX","BI","UNI"]}
+        "capabilities":{"serialmode":["RX","BI","UNI"]},
+        "category":"serial port"
     },
     {
         "name": "serialReadFilter",
@@ -106,7 +127,8 @@
         "type": "filter",
         "default": "",
         "description": "filter for NMEA0183 data when reading from serial\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
-        "capabilities":{"serialmode":["RX","BI","UNI"]}
+        "capabilities":{"serialmode":["RX","BI","UNI"]},
+        "category":"serial port"
     },
     {
         "name": "serialWriteFilter",
@@ -114,14 +136,16 @@
         "type": "filter",
         "default": "",
         "description": "filter for NMEA0183 data when writing to serial\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
-        "capabilities":{"serialmode":["TX","BI","UNI"]}
+        "capabilities":{"serialmode":["TX","BI","UNI"]},
+        "category":"serial port"
     },
     {
         "name": "serverPort",
         "label": "TCP port",
         "type": "number",
         "default": "2222",
-        "description": "the TCP port we listen on"
+        "description": "the TCP port we listen on",
+        "category":"TCP port"
     },
     {
         "name": "maxClients",
@@ -129,63 +153,72 @@
         "type": "number",
         "default": "10",
         "check":"checkMaxClients",
-        "description": "the number of clients we allow to connect to us"
+        "description": "the number of clients we allow to connect to us",
+        "category":"TCP port"
     },
     {
         "name": "sendTCP",
         "label": "NMEA to TCP",
         "type": "boolean",
         "default": "true",
-        "description": "send out NMEA data to connected TCP clients"
+        "description": "send out NMEA data to connected TCP clients",
+        "category":"TCP port"
     },
     {
         "name": "readTCP",
         "label": "NMEA from TCP",
         "type": "boolean",
         "default": "true",
-        "description": "receive NMEA data from connected TCP clients"
+        "description": "receive NMEA data from connected TCP clients",
+        "category":"TCP port"
     },
     {
         "name": "tcpToN2k",
         "label": "TCP to NMEA2000",
         "type": "boolean",
         "default": "true",
-        "description": "convert NMEA0183 from TCP clients to NMEA2000"
+        "description": "convert NMEA0183 from TCP clients to NMEA2000",
+        "category":"TCP port"
     },
     {
         "name": "tcpReadFilter",
         "label": "TCP read Filter",
         "type": "filter",
         "default": "",
-        "description": "filter for NMEA0183 data when reading from TCP\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB"
+        "description": "filter for NMEA0183 data when reading from TCP\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
+        "category":"TCP port"
     },
     {
         "name": "tcpWriteFilter",
         "label": "TCP write Filter",
         "type": "filter",
         "default": "",
-        "description": "filter for NMEA0183 data when writing to TCP\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB"
+        "description": "filter for NMEA0183 data when writing to TCP\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
+        "category":"TCP port"
     },
     {
         "name": "sendSeasmart",
         "label": "Seasmart to TCP",
         "type": "boolean",
         "default": "false",
-        "description": "send NMEA2000 as seasmart to connected TCP clients"
+        "description": "send NMEA2000 as seasmart to connected TCP clients",
+        "category":"TCP port"
     },
     {
         "name": "wifiClient",
         "label": "wifi client",
         "type": "boolean",
         "default": "false",
-        "description": "connect to an external WIFI network"
+        "description": "connect to an external WIFI network",
+        "category":"wifi client"
     },
     {
         "name": "wifiPass",
         "label": "wifi client password",
         "type": "password",
         "default": "",
-        "description": "the password for an external WIFI network"
+        "description": "the password for an external WIFI network",
+        "category":"wifi client"
     },
     {
         "name": "wifiSSID",
@@ -193,14 +226,8 @@
         "type": "string",
         "default": "",
         "check": "checkSSID",
-        "description": "the SSID for an external WIFI network"
-    },
-    {
-        "name": "stopApTime",
-        "type": "number",
-        "default": "0",
-        "check": "checkStopApTime",
-        "description": "stop the access point after that many minutes if not used"
+        "description": "the SSID for an external WIFI network",
+        "category":"wifi client"
     }
     
 
diff --git a/web/index.html b/web/index.html
index 4ab47bd..8a7915f 100644
--- a/web/index.html
+++ b/web/index.html
@@ -8,6 +8,13 @@
   let self=this;
   let lastUpdate=(new Date()).getTime();
   let reloadConfig=false;
+  function addEl(type,clazz,parent,text){
+    let el=document.createElement(type);
+    el.classList.add(clazz);
+    if (text) el.textContent=text;
+    if (parent)parent.appendChild(el);
+    return el;
+  }
   function alertRestart(){
     reloadConfig=true;
     alert("Board reset triggered, reconnect WLAN if necessary");
@@ -265,12 +272,29 @@
         .then(function (capabilities) {
           getJson("config.json")
             .then(function (defs) {
+              let category;
+              let categoryEl;
               let frame = document.querySelector('.configFormRows');
               if (!frame) throw Error("no config form");
               frame.innerHTML = '';
               configDefinitions = defs;
               defs.forEach(function (item) {
                 if (!item.type) return;
+                if (item.category != category || ! categoryEl){
+                  let categoryFrame=addEl('div','category',frame);
+                  let categoryTitle=addEl('div','title',categoryFrame);
+                  let categoryButton=addEl('button','categoryButton',categoryTitle,'v');
+                  addEl('span','label',categoryTitle,item.category);
+                  categoryEl=addEl('div','content',categoryFrame);
+                  categoryEl.classList.add('hidden');
+                  let currentEl=categoryEl;
+                  categoryTitle.addEventListener('click',function(ev){
+                    let rs=currentEl.classList.toggle('hidden');
+                    if (rs) categoryButton.textContent="v";
+                    else categoryButton.textContent="^";
+                  })
+                  category=item.category;
+                }
                 if (item.capabilities !== undefined){
                   for (let capability in item.capabilities){
                     let values=item.capabilities[capability];
@@ -282,16 +306,10 @@
                     if (! found) return;
                   }
                 }
-                let row = document.createElement('div');
-                row.classList.add('row');
+                let row = addEl('div','row',categoryEl);
                 let label = item.label || item.name;
-                let labelEl = document.createElement('span');
-                labelEl.classList.add('label');
-                labelEl.textContent = label;
-                row.appendChild(labelEl);
-                let valueFrame=document.createElement("div");
-                valueFrame.classList.add("value");
-                row.appendChild(valueFrame);
+                addEl('span','label',row,label);
+                let valueFrame=addEl('div','value',row);
                 let valueEl = createInput(item,valueFrame);
                 if (!valueEl) return;
                 valueEl.setAttribute('data-default', item.default);
@@ -300,27 +318,18 @@
                   checkChange(el,row);
                 })
                 if (item.check) valueEl.setAttribute('data-check', item.check);
-                let btContainer=document.createElement("div");
-                btContainer.classList.add("buttonContainer");
-                row.appendChild(btContainer);
-                let bt = document.createElement('button');
-                bt.classList.add('defaultButton');
+                let btContainer=addEl('div','buttonContainer',row);
+                let bt = addEl('button','defaultButton',btContainer,'X');
                 bt.setAttribute('data-default', item.default);
                 bt.addEventListener('click', function (ev) {
                   valueEl.value = valueEl.getAttribute('data-default');
                   let changeEvent=new Event('change');
                   valueEl.dispatchEvent(changeEvent);
                 })
-                bt.textContent = "X";
-                btContainer.appendChild(bt);
-                bt = document.createElement('button');
-                bt.classList.add('infoButton');
+                bt = addEl('button','infoButton',btContainer,'?');
                 bt.addEventListener('click', function (ev) {
                   showOverlay(item.description);
                 });
-                bt.textContent = "?";
-                btContainer.appendChild(bt);
-                frame.appendChild(row);
               })
               resetForm();
             })
@@ -338,6 +347,22 @@
       text+="</p>";
       showOverlay(text,true);
     });
+  }
+  function handleTab(el){
+    let activeName=el.getAttribute('data-page');
+    if (! activeName) return;
+    let activeTab=document.getElementById(activeName);
+    if (!activeTab) return;
+    let all=document.querySelectorAll('.tabPage');
+    for (let i=0;i<all.length;i++){
+      all[i].classList.add('hidden');
+    }
+    let tabs=document.querySelectorAll('.tab');
+    for (let i=0;i<all.length;i++){
+      tabs[i].classList.remove('active');
+    }
+    el.classList.add('active');
+    activeTab.classList.remove('hidden');
   }  
   window.setInterval(update,1000);
   window.addEventListener('load',function(){
@@ -350,17 +375,31 @@
     cd.addEventListener('change',function(ev){
       showCanDetails(ev.target.checked);
     });
+    let tabs=document.querySelectorAll('.tab');
+    for (let i=0;i<tabs.length;i++){
+      tabs[i].addEventListener('click',function(ev){
+        handleTab(ev.target);
+      });
+    }
     loadConfigDefinitions();
   });
 </script>  
 <style type="text/css">
 .configForm {
-    margin-top: 1em;
-    margin-bottom: 1em;
-    padding-top: 0.5em;
     padding-bottom: 0.5em;
-    border: 1px solid grey;
-    max-width: 40em;
+}
+.configForm .buttons {
+    margin-top: 0.5em;
+}
+.configForm .content>div:nth-child(even) {
+    background-color: rgb(211 211 211 / 43%);
+}
+#statusPage .even {
+    background-color: rgb(211 211 211 / 43%);
+}
+.category .title .label {
+    opacity: 1;
+    margin-left: 1em;
 }
 .changed input{
     color: green
@@ -373,11 +412,13 @@ span.label {
     display: inline-block;
     opacity: 0.6;
 }
-.value {
-    width: 19em;
+.configForm .value {
+    width: 21em;
     display: flex;
     flex-direction: row;
+    margin-bottom: 0.2em;
 }
+
 span#connected {
     display: inline-block;
     background-color: red;
@@ -389,11 +430,16 @@ span#connected.ok{
   background-color: #13ac13;
 }
 .row {
-    margin: 0.5em;
+    padding: 0.5em;
     display: flex;
     flex-direction: row;
     flex-wrap: wrap;
 }
+input,select {
+    border: 1px solid #808080a1;
+    font-size: 0.9em;
+    padding: 0.2em;
+}
 .filter {
     display: inline-block;
 }
@@ -404,6 +450,16 @@ button.infoButton {
     margin-left: 1em;
     vertical-align: bottom;
 }
+.category .title {
+    padding-left: 0.5em;
+    background-color: lightgray;
+    padding-top: 0.3em;
+    padding-bottom: 0.5em;
+    border-bottom: 1px solid darkgray;
+}
+.hidden{
+  display: none !important;
+}
 #canDetails{
   display:none;
 }
@@ -420,9 +476,7 @@ button.infoButton {
     background-color: #80808070;
     display: flex;
 }
-.overlayContainer.hidden{
-  display: none;
-}
+
 div#overlay {
     margin: auto;
     background-color: white;
@@ -443,21 +497,56 @@ div#overlayContent.text{
     flex-direction: row;
     justify-content: end;
 }
+#tabs {
+    display: flex;
+    border-bottom: 1px solid grey;
+    margin-bottom: 0.5em;
+}
+#tabs .tab {
+    background-color: lightgray;
+    padding: 0.5em;
+    border-left: 1px;
+    border-right: 1px;
+    border-top: 1px;
+    border-bottom: 1px;
+    border-color: grey;
+    border-style: solid;
+    opacity: 0.6;
+}
+#tabs .tab.active{
+  opacity: 1;
+}
+.buttons button{
+  padding: 0.5em;
+}
+button#reset{
+  padding: 0.5em;
+}
+h1{
+  margin-bottom: 0;
+}
+
 </style>
 </head>
 <body>
 <div class="main">
 <h1>NMEA 2000 Gateway </h1>
+<div class="row">
+  <span class="label">connected</span>
+  <span class="value" id="connected"></span>
+</div>
+<div id="tabs">
+  <div class="tab active" data-page="statusPage">Status</div>
+  <div class="tab" data-page="configPage">Config</div>
+</div>
+<div id="statusPage" class="tabPage">
 <div class="row">
   <span class="label">VERSION</span>
   <span class="value" id="version">---</span>
   <button class="infoButton" id="converterInfo">?</button> 
 </div>
-<div class="row">
-  <span class="label">connected</span>
-  <span class="value" id="connected"></span>
-</div>
-<div class="row">
+
+<div class="row even">
   <span class="label">Access Point IP</span>
   <span class="value" id="apIp">---</span>
 </div>
@@ -465,19 +554,19 @@ div#overlayContent.text{
   <span class="label"># NMEA2000 messages</span>
   <span class="value" id="numcan">---</span>
 </div>
-<div class="row">
+<div class="row even">
   <span class="label">NMEA2000 details</span>
   <input type="checkbox" id="showCanDetails"></span>
 </div>
 
-<div class="row" id="canDetails">
+<div class="row even" id="canDetails">
 
 </div>
 <div class="row">
   <span class="label"># TCP clients</span>
   <span class="value" id="numClients">---</span>
 </div>
-<div class="row">
+<div class="row even">
   <span class="label">wifi client connected</span>
   <span class="value" id="wifiConnected">---</span>
 </div>
@@ -486,7 +575,8 @@ div#overlayContent.text{
   <span class="value" id="clientIP">---</span>
 </div>
 <button id="reset" >Reset</button>
-<div class="configForm">
+</div>
+<div class="configForm tabPage hidden" id="configPage" >
   <div class="configFormRows">
 
   </div>