JavaScript Menus and Client-Side Behavior in DFM2HTML
JavaScript menus are where a visual HTML editor and client-side scripting meet, and the intersection is trickier than it looks. DFM2HTML produces well-structured HTML that gives menu scripts a clean, predictable DOM to work with. But getting a dropdown navigation system to behave correctly across browsers, pointer devices, and keyboard inputs still requires understanding what the scripts actually do and where the common failure points are. This page covers DFM2HTML's JavaScript menu integration in detail: how the menu system is structured, how to configure hover and click behavior, how to handle keyboard navigation and focus management, what DOM interactions to watch for, and how to keep the HTML underneath the scripts clean and maintainable. It also addresses the most common mistakes in menu behavior that show up in real desktop-built sites. You will find practical examples, configuration notes, and links to the main tutorials and the tutorials section for broader context.
Why Light Scripting Still Matters
There is a tendency in modern web development to treat small, dependency-free JavaScript as a second-class approach. Most frontend frameworks assume you want a full component lifecycle, a virtual DOM, and a build pipeline. For a static site built with DFM2HTML, that is serious overkill. A brochure site with five pages and a dropdown menu does not benefit from React. It benefits from a 40-line script that works in every browser without a module bundler.
Light scripting also has a practical maintenance advantage. When you return to a site a year after building it, a self-contained script that attaches to a class name on a list element is far easier to understand and modify than a framework component with its own state management. The DFM2HTML approach deliberately keeps the JavaScript footprint small for this reason.
How DFM2HTML Structures Menu HTML
The editor generates navigation menus as nested unordered lists. The outer list holds the top-level items. Each item that has children contains a second nested list. This is the standard structure that CSS and JavaScript menu systems expect, and it is also the structure that screen readers handle correctly when ARIA attributes are in place.
A typical DFM2HTML navigation output looks structurally like this:
<nav role="navigation" aria-label="Main menu">
<ul class="dfm-nav">
<li><a href="/index.html">Home</a></li>
<li class="has-sub">
<a href="/features.html" aria-haspopup="true" aria-expanded="false">Features</a>
<ul class="dfm-sub">
<li><a href="/features/editor.html">Editor</a></li>
<li><a href="/features/templates.html">Templates</a></li>
</ul>
</li>
<li><a href="/download.html">Download</a></li>
</ul>
</nav> The classes dfm-nav, has-sub, and dfm-sub are the default hooks the menu scripts use. Understanding this structure is the prerequisite to all the customization options below.
Hover State Configuration
The default DFM2HTML menu script opens submenus on mouse hover. This is the behavior most visitors expect for top-level navigation on desktop browsers. The implementation uses mouseenter and mouseleave events rather than CSS hover states alone, which allows the script to manage timing and prevent the submenu from flickering closed when the cursor briefly leaves the parent item during the transition to the child list.
The hover delay is configurable. The default value is 80 milliseconds, which is fast enough that the menu feels responsive but slow enough to prevent accidental submenu openings when a user scans across the navigation bar. Adjusting this value is done through the menu initialization options:
DFMNav.init({
delay: 80,
closeDelay: 120,
selector: '.dfm-nav'
}); Setting closeDelay higher than delay is important. If the menu closes too quickly when the cursor leaves, users will struggle to move their pointer from the parent item to the submenu. A close delay of 100 to 150 milliseconds is the practical range for most navigation layouts.
Click Behavior and Touch Devices
Hover-only menus break on touch screens. A tap on a top-level item that has a submenu should either open the submenu without navigating, or navigate to the parent page if there is a sensible destination. DFM2HTML handles this through a tap-to-toggle pattern: the first tap opens the submenu, the second tap follows the link.
The implementation detects touch capability and switches behavior accordingly:
if ('ontouchstart' in window) {
// Apply touch-optimized toggle behavior
document.querySelectorAll('.has-sub > a').forEach(function(link) {
link.addEventListener('click', function(e) {
var parent = this.parentElement;
if (!parent.classList.contains('open')) {
e.preventDefault();
parent.classList.add('open');
// Close other open items
document.querySelectorAll('.has-sub.open').forEach(function(item) {
if (item !== parent) item.classList.remove('open');
});
}
});
});
} This pattern keeps the behavior predictable across pointer and touch interactions without requiring different markup for different devices.
Keyboard Navigation and Focus Management
Keyboard accessibility is where many static site menus fall short. The standard requirements for a navigable dropdown menu include: Tab moves focus between top-level items, Enter or Space opens a submenu, arrow keys move through submenu items, Escape closes the open submenu and returns focus to the parent, and Tab past the last submenu item closes the submenu automatically.
DFM2HTML's menu script handles all of these cases. The key event bindings are attached to the list items rather than the links, which allows the script to intercept arrow key behavior without interfering with browser scroll behavior on other elements. The aria-expanded attribute on parent links updates as submenus open and close, providing accurate state information to screen readers.
One common mistake is removing the aria-expanded and aria-haspopup attributes from the editor output to simplify the HTML. These attributes are not decoration. They are the mechanism by which screen reader users know a link has children and whether those children are visible. Removing them makes the navigation inaccessible to users who rely on assistive technology.
DOM Hooks and Script Attachment Points
The DFM2HTML menu script attaches to elements by class name. This has an important implication: if you customize the navigation HTML structure in the editor, you need to preserve the class names the script expects. Removing has-sub from a parent list item, for example, will cause the script to ignore that item entirely and the submenu will never open.
The safest approach when customizing navigation is to work within the editor's navigation tools rather than editing the output HTML directly. If you do edit the output, use the browser's developer tools to verify the classes are intact and the event listeners are attached before publishing.
For deeper understanding of DOM scripting fundamentals and event delegation, the MDN Web Docs guide to JavaScript events provides comprehensive reference material for the techniques the menu scripts use.
Maintaining Usable HTML Around Scripts
Scripts should be additive. A navigation list that works as plain HTML links should still function as a list of plain links when JavaScript is unavailable. The DFM2HTML menu approach respects this principle. When JavaScript is disabled or fails to load, the navigation falls back to a visible list of links with no broken behavior. The only capability that disappears is the animated submenu opening and closing. All links remain accessible.
This degradation behavior is worth testing explicitly. Open your exported site in a browser, disable JavaScript in developer settings, and verify that you can still navigate to every page. If any links become unreachable without JavaScript, there is a structural issue in the navigation HTML that needs to be corrected in the editor before publishing.
Common Mistakes in Menu Behavior
These are the menu problems that come up repeatedly when working with DFM2HTML output:
- Hover timing set too low causing the submenu to close before the cursor reaches it. Fix: increase
closeDelayto 150ms or higher. - Missing
position: relativeon the parent list item causing the submenu to appear in an unexpected location. Fix: verify the CSS for.has-subincludesposition: relative. - Z-index conflicts where the submenu appears behind page content. Fix: ensure the submenu has a higher
z-indexthan the elements beneath it. - Multiple submenus staying open simultaneously. Fix: the close-other-items logic in the click handler must run for both mouse and touch interactions.
- Escape key not closing the submenu. Fix: verify the keydown listener is attached to the document rather than individual items, and that it checks for
event.key === 'Escape'. - Tab focus skipping over submenu items. Fix: submenu items must be focusable and visible in the DOM when the submenu is open, not hidden with
display: nonewhile tab focus is inside the submenu.
Next Steps
For step-by-step menu configuration, including screenshots from the DFM2HTML editor interface, see the JavaScript menu path in the tutorials section. For broader site building guidance, the main tutorial covers the full workflow from template selection through export and publish. The FAQ includes answers to common questions about menu behavior and browser compatibility.