# Skip Navigation

Skip links let keyboard and screen-reader users jump straight to the main regions of the app, past repeated navigation. `SkipNavigation` is an opt-in helper for this. It is not rendered by `Chat`, so you add it yourself as the first focusable element in your layout.

For the prop reference see the [Accessibility guide](/chat/docs/sdk/react/guides/accessibility/#skip-navigation).

## Basic setup

Give your key regions stable DOM ids, then render `SkipNavigation` first with those ids ordered by keyboard priority (the composer usually comes first).

```tsx
import {
  Channel,
  Chat,
  MessageInput,
  MessageList,
  SkipNavigation,
  Window,
} from "stream-chat-react";

export const App = ({ client }) => (
  <Chat client={client}>
    <SkipNavigation
      targetIds={["message-composer", "message-list"]}
      getLinkLabel={(targetId) =>
        targetId === "message-composer"
          ? "Skip to message composer"
          : "Skip to messages"
      }
    />
    <Channel>
      <Window>
        <div id="message-list">
          <MessageList />
        </div>
        <div id="message-composer">
          <MessageInput />
        </div>
      </Window>
    </Channel>
  </Chat>
);
```

The links keep native hash navigation (`href="#message-composer"`) and also move focus programmatically. If a target is not naturally focusable, `SkipNavigation` applies `tabindex="-1"` temporarily and removes it on blur, so focus lands reliably without leaving a stray tab stop behind.

## Styling the links

Skip links are conventionally hidden until focused. Each link carries the `str-chat__skip-navigation-link` class; a `className` you pass is merged in. A common pattern is to position them off-screen and reveal them on `:focus`:

```css
.str-chat__skip-navigation-link {
  position: absolute;
  left: -9999px;
  z-index: 1000;
}

.str-chat__skip-navigation-link:focus {
  left: 1rem;
  top: 1rem;
}
```

## View-aware skip links

When you use [`ChatView`](/chat/docs/sdk/react/components/utility-components/chat-view/) to switch between the channel list and the thread list, the relevant targets differ per view. Read the active view from `useChatViewContext` and compute `targetIds` accordingly.

```tsx
import { SkipNavigation, useChatViewContext } from "stream-chat-react";

const ViewAwareSkipNavigation = () => {
  const { activeChatView } = useChatViewContext();

  const targetIds =
    activeChatView === "threads"
      ? ["thread-composer", "thread-list"]
      : ["message-composer", "channel-list"];

  const getLinkLabel = (targetId: string) => {
    switch (targetId) {
      case "message-composer":
      case "thread-composer":
        return "Skip to message composer";
      case "channel-list":
        return "Skip to channel list";
      case "thread-list":
        return "Skip to thread list";
      default:
        return `Skip to ${targetId}`;
    }
  };

  return <SkipNavigation targetIds={targetIds} getLinkLabel={getLinkLabel} />;
};
```

Render `ViewAwareSkipNavigation` as the first child inside `ChatView` and give the corresponding regions matching ids. Because `SkipNavigation` renders `null` when `targetIds` is empty, a view with no available targets simply shows no links.

<Admonition type="note">

Pass DOM ids without the leading `#`. You can intercept activation by passing an `onClick` handler and calling `event.preventDefault()`, for example to run analytics or a custom focus routine.

</Admonition>


---

This page was last updated at 2026-07-09T16:01:15.839Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react/guides/customization/accessibility/skip-navigation/](https://getstream.io/chat/docs/sdk/react/guides/customization/accessibility/skip-navigation/).