> For the complete documentation index, see [llms.txt](https://docs.akinon.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.akinon.com/akinon-ui/ui-protocol/client-application/configuration/navigation.md).

# Navigation

This allows micro-frontends to redirect users to different routes managed by the shell without direct access to the shell's router.

Client applications can request navigation within the shell application.&#x20;

### <mark style="color:red;">How It Works</mark>

1. Client calls `navigate({ path: '/target-path' })`
2. Request is sent to shell via framebus
3. Shell executes navigation using its router
4. URL changes and appropriate content is rendered

### <mark style="color:red;">Basic Usage</mark>

Use the `navigate` function from `useAppClient`:

```tsx
import { useAppClient } from '@akinon/app-client';

const NavigationExample = () => {
  const { navigate } = useAppClient();

  return (
    <div>
      <button onClick={() => navigate({ path: '/dashboard' })}>
        Dashboard
      </button>
      <button onClick={() => navigate({ path: '/orders' })}>
        Orders
      </button>
      <button onClick={() => navigate({ path: '/settings' })}>
        Settings
      </button>
    </div>
  );
};
```

### <mark style="color:red;">Navigation Payload</mark>

```typescript
interface ShellNavigationPayload {
  path: string;
  external?: boolean;
}
```

| Property   | Type      | Description                                                  |
| ---------- | --------- | ------------------------------------------------------------ |
| `path`     | `string`  | Target path to navigate to (should start with `/`)           |
| `external` | `boolean` | If true, navigates at shell level instead of extension level |

{% hint style="info" %}
**Understanding `external`:**

* `external: false` (default) → Navigates within extension scope\
  Example: `/dashboard` → `shell.com/en/en-us/extension/1/dashboard`
* `external: true` → Navigates at shell level\
  Example: `/dashboard` → `shell.com/en/en-us/dashboard`
  {% endhint %}

### <mark style="color:red;">Navigation Examples</mark>

#### Simple Navigation

```tsx
const SimpleNav = () => {
  const { navigate } = useAppClient();

  return (
    <nav>
      <a onClick={() => navigate({ path: '/' })}>Home</a>
      <a onClick={() => navigate({ path: '/products' })}>Products</a>
      <a onClick={() => navigate({ path: '/about' })}>About</a>
    </nav>
  );
};
```

#### With Query Parameters

```tsx
const FilteredNavigation = () => {
  const { navigate } = useAppClient();

  const goToFilteredProducts = (category: string) => {
    navigate({ path: `/products?category=${category}&page=1` });
  };

  return (
    <div>
      <button onClick={() => goToFilteredProducts('electronics')}>
        Electronics
      </button>
      <button onClick={() => goToFilteredProducts('clothing')}>
        Clothing
      </button>
    </div>
  );
};
```

#### Dynamic Routes

```tsx
const OrderList = ({ orders }) => {
  const { navigate } = useAppClient();

  const viewOrder = (orderId: string) => {
    navigate({ path: `/orders/${orderId}` });
  };

  return (
    <ul>
      {orders.map(order => (
        <li key={order.id}>
          Order #{order.id}
          <button onClick={() => viewOrder(order.id)}>View</button>
        </li>
      ))}
    </ul>
  );
};
```

#### Shell-Level Navigation

Navigate to shell routes (outside extension scope):

```tsx
const ShellNavigation = () => {
  const { navigate } = useAppClient();

  const goToShellDashboard = () => {
    navigate({ 
      path: '/dashboard',
      external: true 
    });
  };

  return (
    <button onClick={goToShellDashboard}>
      Go to Main Dashboard
    </button>
  );
};
```

### <mark style="color:red;">Navigation from Rich Modals</mark>

{% hint style="warning" %}
When you call `navigate()` from within a rich modal, the shell automatically:

1. Navigates the parent client
2. Closes the modal

To navigate **within** a rich modal without closing it, use your own routing logic (e.g., React Router).
{% endhint %}

```tsx
// Navigation that CLOSES the modal
const ModalContent = () => {
  const { navigate } = useAppClient();

  const goToDetails = () => {
    navigate({ path: '/details' }); // Modal closes, shell navigates
  };

  return <button onClick={goToDetails}>Go to Details</button>;
};

// Navigation WITHIN the modal (stays open)
import { useNavigate } from 'react-router';

const ModalContentWithInternalNav = () => {
  const routerNavigate = useNavigate();

  const goToStep2 = () => {
    routerNavigate('/modal-step-2'); // Modal stays open
  };

  return <button onClick={goToStep2}>Next Step</button>;
};
```

### <mark style="color:red;">Client-Side Navigation</mark>

For fullpage applications, you can also configure internal navigation:

```tsx
import { useNavigate } from 'react-router';
import { AppClientProvider, type FullpageApplicationConfig } from '@akinon/app-client';

const App = () => {
  const routerNavigate = useNavigate();

  const config: FullpageApplicationConfig = {
    isDev: true,
    menu: [
      { path: '/dashboard', label: 'Dashboard' },
      { path: '/orders', label: 'Orders' }
    ],
    navigation: {
      navigate: ({ path }) => routerNavigate(path)
    }
  };

  return (
    <AppClientProvider config={config}>
      <AppContent />
    </AppClientProvider>
  );
};
```

When the shell triggers `NAVIGATE_CHILD` event, your `navigation.navigate` function is called.

### <mark style="color:red;">Programmatic Navigation Patterns</mark>

#### After Form Submission

```tsx
const CreateOrderForm = () => {
  const { navigate, showToast } = useAppClient();

  const handleSubmit = async (data: OrderData) => {
    try {
      const order = await createOrder(data);
      showToast('Order created!', 'success');
      navigate({ path: `/orders/${order.id}` });
    } catch (error) {
      showToast('Failed to create order', 'error');
    }
  };

  return <OrderForm onSubmit={handleSubmit} />;
};
```

#### Conditional Navigation

```tsx
const ProtectedAction = () => {
  const { navigate, data } = useAppClient();

  const handleClick = () => {
    if (data?.user?.role === 'admin') {
      navigate({ path: '/admin/settings' });
    } else {
      navigate({ path: '/access-denied' });
    }
  };

  return <button onClick={handleClick}>Admin Settings</button>;
};
```

#### Navigation with Confirmation

```tsx
const UnsavedChangesGuard = () => {
  const { navigate, showConfirmationDialog } = useAppClient();
  const [hasChanges, setHasChanges] = useState(false);

  const handleNavigate = (path: string) => {
    if (hasChanges) {
      showConfirmationDialog({
        title: 'Unsaved Changes',
        content: 'You have unsaved changes. Are you sure you want to leave?',
        onConfirm: () => navigate({ path }),
        onCancel: () => {}
      });
    } else {
      navigate({ path });
    }
  };

  return (
    <button onClick={() => handleNavigate('/dashboard')}>
      Go to Dashboard
    </button>
  );
};
```

### <mark style="color:red;">Best Practices</mark>

#### 1. Use Meaningful Paths

```tsx
// ✅ Good - descriptive paths
navigate({ path: '/orders/123/details' });
navigate({ path: '/products?category=electronics' });

// ❌ Bad - unclear paths
navigate({ path: '/p/123' });
navigate({ path: '/page1' });
```

#### 2. Handle Navigation Errors

```tsx
const SafeNavigation = () => {
  const { navigate, showErrorMessage } = useAppClient();

  const safeNavigate = (path: string) => {
    try {
      navigate({ path });
    } catch (error) {
      showErrorMessage('Navigation Error', 'Unable to navigate');
    }
  };
};
```

#### 3. Avoid Navigation on Mount

Don't navigate immediately on component mount - let the user interact first:

```tsx
// ❌ Bad - navigates immediately
useEffect(() => {
  navigate({ path: '/somewhere' });
}, []);

// ✅ Good - navigation triggered by user action
const handleClick = () => {
  navigate({ path: '/somewhere' });
};
```

### <mark style="color:red;">Next Steps</mark>

* Actions - Invoke shell actions
* Hooks - Complete useAppClient reference


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.akinon.com/akinon-ui/ui-protocol/client-application/configuration/navigation.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
