# How the Guided Tour Feature Uses localStorage for Persistence in Ontology-Playground

> Learn how Ontology-Playground uses localStorage for persistence in its guided tour. It stores a dismissal flag to conditionally render the tour component.

- Repository: [Microsoft/Ontology-Playground](https://github.com/microsoft/Ontology-Playground)
- Tags: internals
- Published: 2026-07-23

---

**The Ontology-Playground guided tour persists dismissal state by writing a boolean flag to the browser's localStorage under the key `ontology-quest-tour-dismissed`, then checking that key on application mount to conditionally render the tour component.**

The microsoft/Ontology-Playground repository provides an interactive environment for exploring ontologies, featuring a guided onboarding tour that remembers when a user has dismissed it. This persistence mechanism relies entirely on the browser's localStorage API to store a simple boolean flag across sessions. Understanding this implementation reveals how client-side storage creates seamless user experiences without requiring server-side session management.

## Defining the Storage Key

The persistence logic centers on a single constant defined in [`src/components/GuidedTour.tsx`](https://github.com/microsoft/Ontology-Playground/blob/main/src/components/GuidedTour.tsx). This key serves as the unique identifier for the tour's dismissal state in the browser's local storage.

```typescript
const STORAGE_KEY = 'ontology-quest-tour-dismissed';

```

All subsequent read and write operations reference this constant, ensuring consistency across the application.

## Writing the Dismissal State

When a user interacts with the tour's **Skip tour** button or the close × button, the component invokes the `dismiss` callback. This function wraps the localStorage write operation in a `try…catch` block to handle potential errors gracefully, particularly in environments where localStorage might be restricted or unavailable.

```typescript
const dismiss = useCallback(() => {
  try { 
    localStorage.setItem(STORAGE_KEY, 'true'); 
  } catch { 
    /* noop */ 
  }
  onComplete();
}, [onComplete]);

```

The function stores the string `'true'` rather than a boolean, as localStorage only supports string values. After persisting the flag, it notifies the parent component via the `onComplete` prop to handle any additional cleanup or state updates.

## Reading Persistent State

The `isTourDismissed()` helper function, exported from [`src/components/GuidedTour.tsx`](https://github.com/microsoft/Ontology-Playground/blob/main/src/components/GuidedTour.tsx), provides a synchronous way to check whether the user has previously dismissed the tour. It retrieves the stored value and performs a strict equality check against the string `'true'`.

```typescript
export function isTourDismissed(): boolean {
  try { 
    return localStorage.getItem(STORAGE_KEY) === 'true'; 
  } catch { 
    return false; 
  }
}

```

Like the write operation, this function includes error handling that defaults to `false` if localStorage access fails, ensuring the tour remains visible in restricted environments rather than failing silently.

## Bootstrapping the Tour Condition

In [`src/App.tsx`](https://github.com/microsoft/Ontology-Playground/blob/main/src/App.tsx), the root component initializes the tour visibility state using a lazy initialization pattern with `useState`. This approach checks localStorage once during the initial render rather than on every re-render.

```typescript
const [showTour, setShowTour] = useState(() => !isTourDismissed());

```

The component then conditionally renders the `GuidedTour` component based on this boolean state.

```tsx
return (
  <>
    {showTour && <GuidedTour onComplete={() => setShowTour(false)} />}
    {/* …rest of the application… */}
  </>
);

```

If the `isTourDismissed()` function returns `true`—indicating the user previously dismissed the tour—the `showTour` state initializes to `false`, and the tour remains hidden. Otherwise, the tour displays automatically for first-time visitors.

## External Pre-Emptive Dismissal

Beyond user interaction, other scripts within the repository can also suppress the tour. The [`scripts/render-ontology-previews.ts`](https://github.com/microsoft/Ontology-Playground/blob/main/scripts/render-ontology-previews.ts) file sets the same localStorage key to `'true'` programmatically to prevent the tour from appearing during automated rendering processes or specific application modes.

## Summary

- **The Ontology-Playground** uses a single localStorage key (`ontology-quest-tour-dismissed`) to persist tour dismissal across browser sessions.
- **Writes occur** in [`src/components/GuidedTour.tsx`](https://github.com/microsoft/Ontology-Playground/blob/main/src/components/GuidedTour.tsx) through the `dismiss` callback, which wraps `localStorage.setItem()` in error handling.
- **Reads happen** via the exported `isTourDismissed()` function, which returns a boolean based on the stored string value.
- **Initialization** in [`src/App.tsx`](https://github.com/microsoft/Ontology-Playground/blob/main/src/App.tsx) uses lazy state initialization to check persistence before mounting the tour component.
- **Error resilience** is built into both read and write operations, defaulting to visible tour state if localStorage is unavailable.

## Frequently Asked Questions

### What happens if localStorage is disabled in the browser?

Both the `dismiss` and `isTourDismissed` functions include `try…catch` blocks that suppress errors when localStorage access fails. If the browser blocks localStorage, the tour will always appear on page load because `isTourDismissed()` returns `false` by default, and dismissal attempts will silently fail without crashing the application.

### Can users see the tour again after dismissing it?

Users can reset the tour visibility by manually clearing their browser's localStorage for the Ontology-Playground domain, which removes the `ontology-quest-tour-dismissed` key. Alternatively, opening the application in an incognito or private browsing window provides a fresh storage context where the tour will display again.

### Where is the tour dismissal state initialized?

The dismissal check occurs in [`src/App.tsx`](https://github.com/microsoft/Ontology-Playground/blob/main/src/App.tsx) during the initial component mount using `useState(() => !isTourDismissed())`. This lazy initialization pattern ensures the localStorage check runs only once when the application first renders, preventing unnecessary re-checks during component updates.

### Does the tour support multi-device synchronization?

No, the persistence mechanism relies entirely on browser-specific localStorage, which does not sync across devices or browsers. Each device maintains its own independent dismissal state, meaning users will see the tour again when accessing the application from a different device or browser profile for the first time.