A lightweight, database-free navigation component for PHP websites. Menu content lives in an indented text file, nested sections use native HTML details elements, and the included JavaScript remembers section and scroll state in the browser.
PHP 8.0 or newer
A modern browser
No framework, CMS, or database
Copy menu.php, menu.css, menu.js, and menu.txt into your project.
Load menu.css in the page head.
Set $textMenuConfig and include menu.php where the navigation should appear.
Load menu.js near the end of the page body.
x<link rel="stylesheet" href="text-menu/menu.css">
<?php$textMenuConfig = [ 'title' => 'My Site Menu', 'file' => __DIR__ . '/text-menu/menu.txt', 'base_url' => '/my-site/', 'storage_key' => 'my-site-menu',];require __DIR__ . '/text-menu/menu.php';?>
<script src="text-menu/menu.js"></script>Open demo.php through a PHP web server to see a complete example.
xxxxxxxxxxHome, index.php
Products Product One, products/one.php Older Products [closed] Product Archive, products/archive.phpA comma separates a label from its URL.
A line without a comma creates a section heading.
Use exactly four spaces for each nesting level. Tabs are converted to four spaces.
Add [closed] to a heading to make it initially collapsed.
Blank lines and lines beginning with # are ignored.
Absolute URLs, root-relative paths, anchors, query strings, mailto:, and similar schemes are not modified by base_url.
| Option | Default | Purpose |
|---|---|---|
title | Site Menu | Visible navigation heading |
aria_label | Primary navigation | Accessible navigation label |
id | text-menu-navigation | Navigation element ID |
file | Package menu.txt | Menu configuration path |
base_url | Empty | Prefix for relative menu URLs |
storage_key | php-text-menu | Unique browser-storage namespace |
toggle_label | Menu | Mobile toggle text |
external_new_tab | true | Open HTTP(S) links in a new tab |
If a page contains more than one menu, give each one a unique id and storage_key.
Override these CSS custom properties on .tm-menu:
xxxxxxxxxx.tm-menu { --tm-panel: #1b1d1f; --tm-panel-accent: #25282b; --tm-border: rgba(255, 255, 255, 0.16); --tm-accent: #ee9738; --tm-text: #f7f2e9; --tm-muted: #cec4b5;}The mobile layout activates below 760 pixels. Adjust the matching media queries in menu.css and menu.js together if your site uses a different breakpoint.