diff --git a/dsiUnits-js/src/dsiUnitInput.js b/dsiUnits-js/src/dsiUnitInput.js
index 460e2d58b82f6d681161fc7c8360c3961b318fd1..00d7db445f3f733cdd394797ff82cee2778753b7 100644
--- a/dsiUnits-js/src/dsiUnitInput.js
+++ b/dsiUnits-js/src/dsiUnitInput.js
@@ -1,3 +1,4 @@
+// src/dsiUnitInput.js
 import { DSIUnit } from "./dsiUnit.js";
 import { dsiPrefixesHTML, dsiUnitsHTML, dsiKeyWords } from "./unitStrings.js";
 
@@ -13,14 +14,13 @@ export class DSIUnitInput extends HTMLElement {
     constructor() {
         super();
         this.attachShadow({ mode: "open" });
-        // Internal state: store raw value
+        // Internal state: store raw value.
         this._rawValue = "";
-        // Live update flag: if true, update suggestions and rendering on each keystroke.
         this.liveUpdate = true;
-        // Allowed tokens (may be overridden via attribute)
         this.allowedTokens = defaultAllowedTokens;
+        this.selectedSuggestionIndex = -1;
 
-        // Create our elements.
+        // Create elements.
         this.input = document.createElement("input");
         this.input.type = "text";
         this.input.id = "dsiInput";
@@ -31,20 +31,23 @@ export class DSIUnitInput extends HTMLElement {
 
         this.display = document.createElement("div"); // For rendered output on blur.
         this.display.id = "dsiDisplay";
+        this.display.style.cursor = "text"; // Make it clickable for editing.
 
-        // Wrap in a container (position: relative for suggestions).
+        // Container for input and suggestions.
         const container = document.createElement("div");
         container.style.position = "relative";
         container.appendChild(this.input);
         container.appendChild(this.suggestions);
         container.appendChild(this.display);
 
-        // Append styles into the shadow DOM.
+        // Append styles.
         const style = document.createElement("style");
         style.textContent = `
       #dsiInput {
         width: 400px;
         font-family: monospace;
+        padding: 4px;
+        box-sizing: border-box;
       }
       .autocomplete-list {
         position: absolute;
@@ -59,17 +62,23 @@ export class DSIUnitInput extends HTMLElement {
         padding: 4px;
         cursor: pointer;
       }
-      .autocomplete-item:hover {
-        background-color: #eee;
+      .autocomplete-item.selected {
+        background-color: #bde4ff;
       }
       #dsiDisplay {
         margin-top: 5px;
+        padding: 4px;
+        border: 1px solid #ccc;
+        display: none;
+        width: 400px;
+        font-family: monospace;
       }
     `;
         this.shadowRoot.append(style, container);
 
         // Bind event handlers.
         this.onInput = this.onInput.bind(this);
+        this.onKeyDown = this.onKeyDown.bind(this);
         this.onBlur = this.onBlur.bind(this);
         this.onFocus = this.onFocus.bind(this);
     }
@@ -89,25 +98,53 @@ export class DSIUnitInput extends HTMLElement {
     }
 
     connectedCallback() {
-        // Check for external suggestions list.
         const suggestionsAttr = this.getAttribute("suggestions-list");
         if (suggestionsAttr) {
             this.allowedTokens = suggestionsAttr.split(",").map(s => s.trim());
         }
         this.input.addEventListener("input", this.onInput);
+        this.input.addEventListener("keydown", this.onKeyDown);
         this.input.addEventListener("blur", this.onBlur);
         this.input.addEventListener("focus", this.onFocus);
+        this.display.addEventListener("click", this.onFocus);
     }
 
     disconnectedCallback() {
         this.input.removeEventListener("input", this.onInput);
+        this.input.removeEventListener("keydown", this.onKeyDown);
         this.input.removeEventListener("blur", this.onBlur);
         this.input.removeEventListener("focus", this.onFocus);
+        this.display.removeEventListener("click", this.onFocus);
+    }
+
+    // Determine contextual suggestions based on previous complete token.
+    getContextualSuggestions() {
+        const value = this.input.value;
+        const tokens = value.split("\\").filter(Boolean);
+        if (tokens.length <= 1) {
+            return this.allowedTokens;
+        }
+        const prevToken = tokens[tokens.length - 2];
+        if (prevToken in dsiPrefixesHTML) {
+            // After a prefix, suggest only allowed units.
+            return Object.keys(dsiUnitsHTML);
+        } else if (prevToken in dsiUnitsHTML) {
+            // After a unit, suggest all allowed tokens.
+            // If "\per" exists in the value, omit "per".
+            if (value.includes("\\per")) {
+                return this.allowedTokens.filter(token => token !== "per");
+            }
+            return this.allowedTokens;
+        } else if (prevToken === "per" || prevToken === "tothe") {
+            return this.allowedTokens;
+        } else {
+            return this.allowedTokens;
+        }
     }
 
     onInput(e) {
-        // Store the raw value.
         this._rawValue = this.input.value;
+        this.selectedSuggestionIndex = -1;
         this.updateSuggestions();
         if (this.liveUpdate) {
             this.renderOutput();
@@ -117,19 +154,29 @@ export class DSIUnitInput extends HTMLElement {
     updateSuggestions() {
         const cursorPos = this.input.selectionStart;
         const value = this.input.value;
+        // Check: if caret is inside the braces of a "tothe" token, do not show suggestions.
+        const regexTothe = /\\tothe\{([^}]*)$/;
         const substring = value.substring(0, cursorPos);
-        // Look for a pattern: a backslash followed by at least one letter at the end.
-        const regex = /\\([a-zA-Z]+)$/;
+        const matchTothe = substring.match(regexTothe);
+        if (matchTothe) {
+            this.suggestions.style.display = "none";
+            return;
+        }
+
+        // Use regex to capture current token (may be empty).
+        const regex = /\\([a-zA-Z]*)$/;
         const match = substring.match(regex);
+        let currentToken = "";
         if (match) {
-            const currentToken = match[1];
-            const suggestions = this.allowedTokens.filter(token =>
-                token.startsWith(currentToken)
-            );
-            this.showSuggestions(suggestions, substring.length - currentToken.length);
-        } else {
-            this.suggestions.style.display = "none";
+            currentToken = match[1]; // might be empty
         }
+        // Determine suggestions based on context.
+        const contextSuggestions = this.getContextualSuggestions();
+        const suggestions = currentToken === ""
+            ? contextSuggestions
+            : contextSuggestions.filter(token => token.startsWith(currentToken));
+        this.selectedSuggestionIndex = suggestions.length > 0 ? 0 : -1;
+        this.showSuggestions(suggestions, value.length - currentToken.length);
     }
 
     showSuggestions(list, tokenStartIndex) {
@@ -138,30 +185,81 @@ export class DSIUnitInput extends HTMLElement {
             this.suggestions.style.display = "none";
             return;
         }
-        list.forEach(token => {
+        list.forEach((token, index) => {
             const item = document.createElement("div");
             item.textContent = "\\" + token;
             item.className = "autocomplete-item";
+            if (index === this.selectedSuggestionIndex) {
+                item.classList.add("selected");
+            }
             item.addEventListener("mousedown", (e) => {
                 e.preventDefault();
-                const value = this.input.value;
-                const before = value.substring(0, tokenStartIndex);
-                const after = value.substring(this.input.selectionStart);
-                this.input.value = before + "\\" + token + after;
-                this._rawValue = this.input.value;
-                this.suggestions.style.display = "none";
-                this.input.focus();
-                this.renderOutput();
+                this.acceptSuggestion(token, tokenStartIndex);
             });
             this.suggestions.appendChild(item);
         });
         this.suggestions.style.display = "block";
     }
 
+    onKeyDown(e) {
+        if (this.suggestions.style.display !== "none") {
+            const items = this.suggestions.querySelectorAll(".autocomplete-item");
+            if (e.key === "ArrowDown") {
+                e.preventDefault();
+                if (items.length > 0) {
+                    this.selectedSuggestionIndex = (this.selectedSuggestionIndex + 1) % items.length;
+                    this.updateSuggestionSelection();
+                }
+            } else if (e.key === "ArrowUp") {
+                e.preventDefault();
+                if (items.length > 0) {
+                    this.selectedSuggestionIndex = (this.selectedSuggestionIndex - 1 + items.length) % items.length;
+                    this.updateSuggestionSelection();
+                }
+            } else if (["Enter", "Tab", "ArrowRight"].includes(e.key)) {
+                if (this.selectedSuggestionIndex !== -1) {
+                    e.preventDefault();
+                    const selectedItem = items[this.selectedSuggestionIndex];
+                    const token = selectedItem.textContent.slice(1); // remove backslash
+                    const tokenStartIndex = this.input.value.lastIndexOf("\\");
+                    this.acceptSuggestion(token, tokenStartIndex);
+                }
+            }
+        }
+    }
+
+    updateSuggestionSelection() {
+        const items = this.suggestions.querySelectorAll(".autocomplete-item");
+        items.forEach((item, idx) => {
+            if (idx === this.selectedSuggestionIndex) {
+                item.classList.add("selected");
+            } else {
+                item.classList.remove("selected");
+            }
+        });
+    }
+
+    acceptSuggestion(token, tokenStartIndex) {
+        const value = this.input.value;
+        const before = value.substring(0, tokenStartIndex);
+        const after = value.substring(this.input.selectionStart);
+        if (token === "tothe") {
+            // Append {} and place caret inside.
+            this.input.value = before + "\\" + token + "{}" + after;
+            this._rawValue = this.input.value;
+            const newPos = before.length + token.length + 2;
+            this.input.setSelectionRange(newPos, newPos);
+        } else {
+            this.input.value = before + "\\" + token + after;
+            this._rawValue = this.input.value;
+        }
+        this.suggestions.style.display = "none";
+        this.renderOutput();
+    }
+
     renderOutput() {
         try {
             const unit = new DSIUnit(this.input.value);
-            // Display the rendered output using the DSIUnit's toHTML().
             this.display.innerHTML = unit.toHTML();
             if (unit.warnings && unit.warnings.length > 0) {
                 this.display.title = unit.warnings.join("; ");
@@ -174,7 +272,6 @@ export class DSIUnitInput extends HTMLElement {
     }
 
     onBlur(e) {
-        // On blur, hide the input and show the rendered output.
         this.renderOutput();
         this.input.style.display = "none";
         this.display.style.display = "block";
@@ -182,18 +279,17 @@ export class DSIUnitInput extends HTMLElement {
     }
 
     onFocus(e) {
-        // On focus, restore the raw value for editing.
         this.input.style.display = "block";
         this.display.style.display = "none";
         this.input.value = this._rawValue;
+        this.input.focus();
+        this.input.setSelectionRange(this.input.value.length, this.input.value.length);
     }
 
-    // Expose the current raw value.
     get value() {
         return this._rawValue;
     }
 
-    // Allow setting live update mode.
     set live(value) {
         this.liveUpdate = Boolean(value);
     }
diff --git a/dsiUnits-js/tests/visual_test.html b/dsiUnits-js/tests/visual_test.html
index 696c5c852840040e8b1b7313938cfcdc61573e73..52ac585b4badac379b7c799fadf482bf6468cbd7 100644
--- a/dsiUnits-js/tests/visual_test.html
+++ b/dsiUnits-js/tests/visual_test.html
@@ -89,6 +89,9 @@
             display: block;
             margin-bottom: 40px;
         }
+        .autocomplete-item.selected {
+            background-color: #bde4ff;
+        }
     </style>
 </head>
 <body>