# Navigation

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: 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:

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

The question should be specific, self-contained, and written in natural language.
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.
