When navigation returns to its beginning after a page change, readers may have to find the same subject again. K-POP PULSE’s historical changes combine the list into one rail and read its actual CSS direction to keep horizontal and vertical positions separately. I developed that judgment into a small module for other websites.
The shared files are newly written teaching code and a synthetic example, rather than recovered production files. Core selection, position and storage-failure behavior has been checked. Desktop, narrow-screen and keyboard interaction review is still pending. The module leaves a starting point for verifying the actual navigation flow of its destination site.
Keep subject identity separate from the place being browsed
The selected subject connects to what a page displays. The position in the menu connects to which part of a list someone was browsing. Saving only an identifier loses the scroll context; saving only an offset can be misread as another subject after reordering.
The new core keeps selectedId and x/y positions separately. Pass the identifier matching the actual route instead of redirecting visitors to a remembered selection. The integrating site remains responsible for checking that selected navigation and the page’s content agree.
Let CSS choose the direction of a single list
Rendering the same list again for each screen size adds another set of elements and events to maintain. This example changes one nav between row and column. The controller reads computed flex-direction to choose its axis, keeping the layout criterion aligned with the rendered element.
The CSS below provides an integration starting point. Adapt the breakpoint and maximum height to the site’s content and list length. The module supports normal LTR horizontal and vertical layouts. Reverse directions, RTL, virtualization and drag sorting are outside its implementation; it does not reproduce every feature of the original website.
Explore the implementation
New CSS example changing the direction of one list; adapt the breakpoint to the site.
.subject-rail { display:flex; flex-direction:row; direction:ltr; overflow:auto; }
.subject-rail > * { flex:0 0 auto; }
@media (min-width: 900px) {
.subject-rail { flex-direction:column; max-height:20rem; }
}Remember each axis and clamp to the available distance
One hundred horizontal pixels and one hundred vertical pixels do not describe the same view. Returning to an orientation restores its separate value. If content becomes shorter or the viewport larger, restoration clamps the saved value to the distance currently available.
Identity uses a stable value rather than an array index. Reordering retains selection by ID; removing the selected ID clears it. Updating the pure state’s known IDs differs from replacing screen elements. When the DOM children change, destroy the old connection and attach the replacement list.
Keep current interaction available when storage fails
Reading or writing browser storage can fail. The module catches those failures and continues in the mounted instance’s memory. Selection and position remain usable there, without promising persistence after reconnecting or reloading. The example explicitly displays its current storage mode.
The article’s HTML example runs in a separate frame from the administrator. An unavailable storage origin is not a reason to share administrative privileges. Choose the storage lifetime and a site-specific key, acquire localStorage in a guarded block, and pass it to the adapter. Navigation memory has no reason to contain login data or secrets.
Leave real routing with the integrating site
The connection example below passes a real route ID and a separate storage key. The site must supply currentRouteSubjectId from its actual address. Native link navigation is not intercepted. The numbered demo buttons only change example text, and reconnect simulates remounting instead of testing a real cross-page transition.
Scroll saves are grouped per animation frame. Selection and pagehide flush the current position immediately. Destroy removes listeners, the observer and any scheduled frame. In the integrating website, follow back navigation, reload, width changes, movement to another list and keyboard focus as a connected flow.
Explore the implementation
New integration example. Supply the current route ID from the actual site.
import {attachRail} from './rail-memory.mjs';
let storage = null;
try { storage = window.localStorage; } catch {}
const controller = attachRail(document.querySelector('.subject-rail'), {
key: 'your-site:subject-rail:v1',
storage,
currentId: currentRouteSubjectId // Supply the actual route's ID, or null.
});
// Before replacing the list DOM:
// controller.destroy(); then attach the replacement rail.Download the code and check it against your workflow
The package includes the core module, standalone Korean and English HTML, documentation and Node checks. Sixteen synthetic core checks passed, including selection, separate axis values, shortened bounds, malformed storage, changing IDs and storage failures. They do not replace rendered layout, event-order or real cross-page persistence checks.
The Studio browser checks exercise direction changes, actual scrolling, subject selection and per-axis restoration in Korean and English frames at 960px and 390px. Reconnecting the public sandbox resets its in-memory state as described. Separately, the exact core runs against real browser storage under a fresh isolated test key; selection and both offsets survive a reload, and the key is restored afterward. Real site navigation, drag ordering and a whole physical-device screen remain outside this check.