diff --git a/pd/nw/css/default.css b/pd/nw/css/default.css
index 522113d39e0fc74d211cf9225974a1a44fe1fb7e..caeb671e909726d140dfc25302e007664689c14a 100644
--- a/pd/nw/css/default.css
+++ b/pd/nw/css/default.css
@@ -343,6 +343,7 @@ text {
     border:1px solid #bbb;
     padding: 12px;
     margin: 12px;
+    box-shadow: 7px 7px 5px grey;
 }
 
 /* Common to all dialogs */
@@ -472,3 +473,120 @@ div.y2 {
 .disabled {
     color: #aaa;
 }
+
+/* Preferences dialog */
+
+#prefs_html_element {
+/*    height: 100%; */
+    margin: 0px;
+    padding: 0px;
+    height: 100vh;
+}
+
+#prefs_body {
+    margin-left: 0px;
+    margin-right: 0px;
+    margin-top: 0px;
+    margin-bottom: 0px;
+/*    height: 100%; */
+    padding: 0px;
+}
+
+#prefs_container {
+    display: table;
+}
+
+/* Main tab widget */
+.prefs_tab_group {
+    /* I needed to get this div to expand with the inner div content so
+       that I could resize the prefs window to display the content without
+       a scrollbar. I just played stackexchange roulette until I found
+       something that worked. I have no idea why absolute positioning
+       solves my problem, nor do I have time to become a CSS wizard just
+       to get this single thing to work. */
+    display: table;
+    width: 90%;
+/*    height: 90vh; */
+}
+
+/* Configure the radio buttons to hide off-screen */
+.prefs_tab {
+    position: absolute;
+    left:-100px;
+    top:-100px;
+}
+
+/* Configure labels to look like tabs */
+.prefs_tab + label {
+    /* inline-block such that the label can be given dimensions */
+    display: inline-block;
+    /* A nice curved border around the tab */
+    border: 1px solid black;
+    /* the bottom border is handled by the tab content div */
+    border-bottom: 0;
+    /* Padding around tab text */
+    padding: 5px 10px;
+    /* put a small margin to the left to make the first tab clear */
+    margin-left: 4px;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    /* Set the background color to default gray (non-selected tab) */
+    background-color:#ddd;
+    height: 5vh;
+}
+
+/* Focused tabs */
+.prefs_tab:focus + label {
+    border: 1px dashed black;
+}
+
+/* Checked tabs must be white with the bottom border removed */
+.prefs_tab:checked + label {
+    background-color:white;
+    font-weight: bold;
+    border-bottom: 1px solid white;
+    margin-bottom: -1px;
+}
+
+/* The tab content must fill the widgets size and have a nice border */
+.prefs_tab_group > div {
+    display: none;
+    border-top: 1px solid black;
+/*    border-bottom: 1px solid black; */
+    background-color: white;
+/*    padding: 10px 10px; */
+    padding: 0px;
+    margin: 0px;
+    height: 100%;
+/*    height: 95%; */
+/*    margin-bottom: -20px; */
+/*    overflow: auto; */
+
+/*    box-shadow: 0 0 20px #444;
+    -moz-box-shadow: 0 0 20px #444;
+    -webkit-box-shadow: 0 0 20px #444;
+*/
+/*    border-radius: 0 5px 5px 5px;
+    -moz-border-radius: 0 5px 5px 5px;
+    -webkit-border-radius: 0 5px 5px 5px;
+*/
+}
+
+/* This matches tabs displaying to their associated radio inputs */
+.tab1:checked ~ .tab1, .tab2:checked ~ .tab2, .tab3:checked ~ .tab3 {
+    display: table;
+    padding: 8px;
+    width: 100%;
+/*    height: 100%; */
+    height: 78vh;
+}
+
+#prefs_buttons {
+    display: table;
+    height: 10vh;
+    padding: 0px;
+    margin: 0px;
+    margin-top: -10px;
+    margin-bottom: -10px;
+    padding: 30px;
+}
diff --git a/pd/nw/dialog_prefs.html b/pd/nw/dialog_prefs.html
index 6d00bcf4b5b70fa434fc91baa752d9b6748a1d07..d8bade24951275a03e5d5fc271f32c3193b0fdb2 100644
--- a/pd/nw/dialog_prefs.html
+++ b/pd/nw/dialog_prefs.html
@@ -1,30 +1,42 @@
 <!DOCTYPE html>
-<html>
+<html id="prefs_html_element">
   <head>
     <link id="page_style" rel="stylesheet" type="text/css" href="css/default.css">
   </head>
-  <body class="dialog_body">
-    <div class="container noselect">
-      <div class="menu">
-        <span data-i18n="[title]prefs.heading.audio_tt">
-          <a onclick="display_pref('audio');"
-             data-i18n="prefs.heading.audio">
-          </a> 
-        </span>
-        <span data-i18n="[title]prefs.heading.midi_tt">
-          <a onclick="display_pref('midi');"
-             data-i18n="prefs.heading.midi"></a> 
-        </span>
-        <span data-i18n="[title]prefs.heading.gui_tt">
-          <a onclick="display_pref('gui');"
-             data-i18n="prefs.heading.gui"></a> 
-        </span>
-      </div>
-
-      <fieldset id="audio">
-        <legend data-i18n="prefs.heading.audio"></legend>
-        <select id="audio_api" onchange="change_api(this);">
-        </select>
+  <body class="dialog_body" id="prefs_body">
+<div class="container noselect prefs_container">
+    <div class="prefs_tab_group">
+      <input type="radio"
+             name="prefs_radio_group"
+             id="audio_tab_radio"
+             class="tab1 prefs_tab"
+             checked="checked" />
+      <label for="audio_tab_radio" data-i18n="[title]prefs.heading.audio_tt">
+        <span data-i18n="prefs.heading.audio"></span>
+      </label>
+
+      <input type="radio"
+             name="prefs_radio_group"
+             id="midi_tab_radio"
+             class="tab2 prefs_tab"/>
+      <label for="midi_tab_radio" data-i18n="[title]prefs.heading.midi_tt">
+        <span data-i18n="prefs.heading.midi"></span>
+      </label>
+
+      <input type="radio"
+             name="prefs_radio_group"
+             id="gui_tab_radio"
+             class="tab3 prefs_tab"/>
+      <label for="gui_tab_radio" data-i18n="[title]prefs.heading.gui_tt">
+        <span data-i18n="prefs.heading.gui"></span>
+      </label>
+
+      <div class="tab1">
+        <label data-i18n="[title]prefs.audio.api_tt">
+          <span data-i18n="prefs.audio.api"></span>
+          <select id="audio_api" onchange="change_api(this);">
+          </select>
+        </label>
         <br/>
         <label data-i18n="[title]prefs.audio.sr_tt">
           <span data-i18n="prefs.audio.sr"></span>
@@ -48,16 +60,18 @@
             <input type="checkbox" id="callback" name="callback">
           </label>
         </div>
-
-        <select id="blocksize"
-                onchange="attr_change(this);">
-          <option value="64">64</option>
-          <option value="128">128</option>
-          <option value="256">256</option>
-          <option value="512">512</option>
-          <option value="1024">1024</option>
-          <option value="2048">2048</option>
-        </select>
+        <label data-i18n="[title]prefs.audio.blocksize_tt">
+          <span data-i18n="prefs.audio.blocksize"></span>
+          <select id="blocksize"
+                  onchange="attr_change(this);">
+            <option value="64">64</option>
+            <option value="128">128</option>
+            <option value="256">256</option>
+            <option value="512">512</option>
+            <option value="1024">1024</option>
+            <option value="2048">2048</option>
+          </select>
+        </label>
         <br/>
         <table>
           <tr>
@@ -181,11 +195,9 @@
             </td>
           </tr>
         </table>
+      </div>
 
-      </fieldset>
-
-      <fieldset id="midi">
-        <legend data-i18n="prefs.heading.midi"></legend>
+      <div class="tab2">
         <select id="midi_api" onchange="change_api(this);">
         </select>
         <br/>
@@ -206,50 +218,46 @@
         <br/>
         <select id="midi_out4" onchange="dev_change(this);"></select>
         <br/>
+      </div>
 
-      </fieldset>
-
-      <fieldset id="gui">
-        <legend data-i18n="prefs.heading.gui"></legend>
-
-          <label data-i18n="[title]prefs.gui.presets.gui_preset_tt">
-            <span data-i18n="prefs.gui.presets.gui_preset"></span>
-          </label>
-          <select id="gui_preset" onchange="gui_preset_change(this);">
-            <option data-i18n="prefs.gui.presets.default" value="default">
-            </option>
-            <option data-i18n="prefs.gui.presets.inverted" value="inverted">
-            </option>
-            <option data-i18n="prefs.gui.presets.vanilla" value="vanilla">
-            </option>
-            <option data-i18n="prefs.gui.presets.vanilla_inverted" value="vanilla_inverted">
-            </option>
-            <option data-i18n="prefs.gui.presets.extended" value="extended">
-            </option>
-            <option data-i18n="prefs.gui.presets.c64" value="c64">
-            </option>
-            <option data-i18n="prefs.gui.presets.subdued" value="subdued">
-            </option>
-            <option data-i18n="prefs.gui.presets.strongbad" value="strongbad">
-            </option>
-          </select>
-
-      </fieldset>
-
+      <div class="tab3">
+        <label data-i18n="[title]prefs.gui.presets.gui_preset_tt">
+          <span data-i18n="prefs.gui.presets.gui_preset"></span>
+        </label>
+        <select id="gui_preset" onchange="gui_preset_change(this);">
+          <option data-i18n="prefs.gui.presets.default" value="default">
+          </option>
+          <option data-i18n="prefs.gui.presets.inverted" value="inverted">
+          </option>
+          <option data-i18n="prefs.gui.presets.vanilla" value="vanilla">
+          </option>
+          <option data-i18n="prefs.gui.presets.vanilla_inverted" value="vanilla_inverted">
+          </option>
+          <option data-i18n="prefs.gui.presets.extended" value="extended">
+          </option>
+          <option data-i18n="prefs.gui.presets.c64" value="c64">
+          </option>
+          <option data-i18n="prefs.gui.presets.subdued" value="subdued">
+          </option>
+          <option data-i18n="prefs.gui.presets.strongbad" value="strongbad">
+          </option>
+        </select>
+      </div>
+    </div>
 
-    <div class="submit_buttons">
-      <button type="button" onClick="ok()" data-i18n="[title]prefs.ok_tt">
-        <span data-i18n="prefs.ok"></span>
-      </button>
-      <button type="button" onClick="apply()" data-i18n="[title]prefs.apply_tt">
-      <span data-i18n="prefs.apply"></span>
-      </button>
-      <button type="button" onClick="cancel()" data-i18n="[title]prefs.close_tt">
-      <span data-i18n="prefs.close"></span>
-      </button>
+      <div class="submit_buttons prefs_buttons">
+        <button type="button" onClick="ok()" data-i18n="[title]prefs.ok_tt">
+          <span data-i18n="prefs.ok"></span>
+        </button>
+        <button type="button" onClick="apply()" data-i18n="[title]prefs.apply_tt">
+        <span data-i18n="prefs.apply"></span>
+        </button>
+        <button type="button" onClick="cancel()" data-i18n="[title]prefs.close_tt">
+        <span data-i18n="prefs.close"></span>
+        </button>
       </div>
 
-    </div>
+</div>
   <script>
 "use strict";
 var gui = require("nw.gui");
@@ -271,17 +279,6 @@ function ok() {
     cancel();
 }
 
-function display_pref(type) {
-    pdgui.post("here i am with " + type);
-    var all, i, this_elem;
-    all = document.getElementsByTagName("fieldset");
-    this_elem = document.getElementById(type);
-    for (i = 0; i < all.length; i++) {
-        all[i].style.setProperty("display", "none");
-    }
-        this_elem.style.setProperty("display", "inline");
-}
-
 function gui_preset_change(elem) {
     pdgui.skin.set(elem.value);
 }
@@ -573,8 +570,6 @@ function register_window_id(gfxstub, attr_arrays) {
     add_events(gfxstub);
     translate_form();
 
-    // default to audio preference panel
-    display_pref("audio");
     // We don't turn on rendering of the "container" div until
     // We've finished displaying all the spans and populating the
     // labels and form elements.  That makes it more efficient and
diff --git a/pd/nw/locales/en/translation.json b/pd/nw/locales/en/translation.json
index 5ad40a2471d8bf31090aa043d8fa4570d52f77e0..3a2196c2a8cca3205beafce3d30d2bfe9468e9be 100644
--- a/pd/nw/locales/en/translation.json
+++ b/pd/nw/locales/en/translation.json
@@ -322,7 +322,9 @@
       "gui": "GUI",
       "gui_tt": "settings for the user interface",
       "audio": "audio",
-      "midi": "MIDI"
+      "audio_tt": "configure the audio devices",
+      "midi": "MIDI",
+      "midi_tt": "configure MIDI devices"
     },
     "gui": {
       "presets": {
@@ -340,10 +342,14 @@
       }
     },
     "audio": {
+      "api": "audio api",
+      "api_tt": "audio backend or server to use to process audio",
       "sr": "sample rate",
       "sr_tt": "number of samples per second",
       "advance": "delay",
       "advance_tt": "delay",
+      "blocksize": "blocksize",
+      "blocksize_tt": "number of samples in a block to be delivered to or received from the audio api",
       "channels": "channels",
       "channels_tt": "number of channels for this device"
     },
diff --git a/pd/nw/pdgui.js b/pd/nw/pdgui.js
index f408553d59909e13f7aa19429e744d39ad1b5a07..bf263e62c0c74a10b348e420c1ce68b53980edb7 100644
--- a/pd/nw/pdgui.js
+++ b/pd/nw/pdgui.js
@@ -3315,7 +3315,7 @@ function gui_pd_dsp(state) {
 
 function open_prefs() {
     if (!dialogwin["prefs"]) {
-        nw_create_window("prefs", "prefs", 265, 350, 0, 0, null);
+        nw_create_window("prefs", "prefs", 265, 400, 0, 0, null);
     }
 }