diff --git a/packages/web-react/src/components/Navigation/Navigation.tsx b/packages/web-react/src/components/Navigation/Navigation.tsx
new file mode 100644
index 0000000000..b27049daec
--- /dev/null
+++ b/packages/web-react/src/components/Navigation/Navigation.tsx
@@ -0,0 +1,22 @@
+'use client';
+
+import classNames from 'classnames';
+import React from 'react';
+import { useStyleProps } from '../../hooks';
+import { SpiritNavigationProps } from '../../types';
+import { useNavigationStyleProps } from './useNavigationStyleProps';
+
+const Navigation = (props: SpiritNavigationProps): JSX.Element => {
+ const { children, ...restProps } = props;
+
+ const { classProps } = useNavigationStyleProps();
+ const { styleProps, props: otherProps } = useStyleProps(restProps);
+
+ return (
+
+
+
+ );
+};
+
+export default Navigation;
diff --git a/packages/web-react/src/components/Navigation/NavigationItem.tsx b/packages/web-react/src/components/Navigation/NavigationItem.tsx
new file mode 100644
index 0000000000..bb32fff3ca
--- /dev/null
+++ b/packages/web-react/src/components/Navigation/NavigationItem.tsx
@@ -0,0 +1,19 @@
+'use client';
+
+import React from 'react';
+import { useStyleProps } from '../../hooks';
+import { SpiritNavigationItemProps } from '../../types';
+
+const NavigationItem = (props: SpiritNavigationItemProps): JSX.Element => {
+ const { children, ...restProps } = props;
+
+ const { styleProps, props: otherProps } = useStyleProps(restProps);
+
+ return (
+
+ {children}
+
+ );
+};
+
+export default NavigationItem;
diff --git a/packages/web-react/src/components/Navigation/NavigationLink.tsx b/packages/web-react/src/components/Navigation/NavigationLink.tsx
new file mode 100644
index 0000000000..c47c532ac5
--- /dev/null
+++ b/packages/web-react/src/components/Navigation/NavigationLink.tsx
@@ -0,0 +1,43 @@
+'use client';
+
+import classNames from 'classnames';
+import React, { ElementType, forwardRef } from 'react';
+import { useStyleProps } from '../../hooks';
+import { PolymorphicRef, SpiritNavigationLinkProps } from '../../types';
+import { useNavigationLinkProps } from './useNavigationLinkProps';
+import { useNavigationLinkStyleProps } from './useNavigationLinkStyleProps';
+
+const defaultProps: Partial = {
+ elementType: 'a',
+};
+
+/* We need an exception for components exported with forwardRef */
+/* eslint no-underscore-dangle: ['error', { allow: ['_NavigationLink'] }] */
+const _NavigationLink = (
+ props: SpiritNavigationLinkProps,
+ ref: PolymorphicRef,
+): JSX.Element => {
+ const propsWithDefaults = { ...defaultProps, ...props };
+ const { elementType = defaultProps.elementType as ElementType, children, ...restProps } = propsWithDefaults;
+ const ElementTag = propsWithDefaults.isDisabled ? 'span' : elementType;
+
+ const { navigationLinkProps } = useNavigationLinkProps(propsWithDefaults);
+ const { classProps, props: modifiedProps } = useNavigationLinkStyleProps(restProps);
+ const { styleProps, props: otherProps } = useStyleProps(modifiedProps);
+
+ return (
+
+ {children}
+
+ );
+};
+
+const NavigationLink = forwardRef>(_NavigationLink);
+
+export default NavigationLink;
diff --git a/packages/web-react/src/components/Navigation/README.md b/packages/web-react/src/components/Navigation/README.md
new file mode 100644
index 0000000000..4dd8ce4653
--- /dev/null
+++ b/packages/web-react/src/components/Navigation/README.md
@@ -0,0 +1,134 @@
+# Navigation
+
+The `Navigation` component is a container for the navigation links of the application.
+
+It consists of a these parts:
+
+- [Navigation](#navigation)
+- [NavigationItem](#navigation-item)
+- [NavigationLink](#navigation-link)
+
+## Navigation
+
+The `Navigation` is a `nav` wrapper for navigation items.
+
+```jsx
+import { Navigation } from '@lmc-eu/spirit-web-react';
+
+{/* Navigation items go here */} ;
+```
+
+It centres its children vertically, and if the children do not include `NavigationLink` components,
+it will apply a gap between them.
+
+ℹ️ Don't forget to add the `aria-label` attribute to the `Navigation` component for correct accessible state.
+
+### API
+
+| Name | Type | Default | Required | Description |
+| ---------- | --------------------------------------------------------------------------------------- | ------- | -------- | ------------------------- |
+| `children` | `ReactElement` \| `ReactElement` \| Array of these types | `null` | ✓ | Content of the Navigation |
+
+The components accept [additional attributes][readme-additional-attributes].
+If you need more control over the styling of a component, you can use [style props][readme-style-props]
+and [escape hatches][readme-escape-hatches].
+
+## Navigation Item
+
+The `NavigationItem` is a container for navigation links.
+
+```jsx
+import { NavigationItem } from '@lmc-eu/spirit-web-react';
+
+{/* Navigation links go here */} ;
+```
+
+### API
+
+| Name | Type | Default | Required | Description |
+| ---------- | ----------------------- | ------- | -------- | ----------------------------- |
+| `children` | `string` \| `ReactNode` | `null` | ✓ | Content of the NavigationItem |
+
+The components accept [additional attributes][readme-additional-attributes].
+If you need more control over the styling of a component, you can use [style props][readme-style-props]
+and [escape hatches][readme-escape-hatches].
+
+## Navigation Link
+
+The `NavigationLink` is component that is styled to be used as a navigation link.
+
+```jsx
+import { NavigationLink } from '@lmc-eu/spirit-web-react';
+
+Link ;
+```
+
+It can obtain `isSelected` or `isDisabled` states by adding the respective props.
+
+```jsx
+Selected Link
+Disabled Link
+```
+
+ℹ️ Don't forget to add the `aria-current="page"` attribute for correct accessible state if selected.
+
+ℹ️ Please note that in the `isDisabled` state the `NavigationLink` will be an `span` tag.
+
+If the `NavigationLink` is inside a [`UNSTABLE_Header`][web-react-unstable-header] component, it will
+inherit the height of the `Header`.
+
+### API
+
+| Name | Type | Default | Required | Description |
+| ------------- | --------------------------------- | ------- | -------- | ----------------------------- |
+| `children` | `string` \| `ReactNode` | `null` | ✓ | Content of the NavigationLink |
+| `elementType` | `ElementType` | `a` | ✕ | Type of element used as |
+| `href` | `string` | - | ✕ | URL of the link |
+| `isDisabled` | `boolean` | `false` | ✕ | Whether the link is disabled |
+| `isSelected` | `boolean` | `false` | ✕ | Whether the link is selected |
+| `ref` | `ForwardedRef` | — | ✕ | Anchor element reference |
+| `target` | `string` | `null` | ✕ | Link target |
+
+The components accept [additional attributes][readme-additional-attributes].
+If you need more control over the styling of a component, you can use [style props][readme-style-props]
+and [escape hatches][readme-escape-hatches].
+
+### Full Example
+
+With NavigationLink components:
+
+```jsx
+
+
+
+ Selected Link
+
+
+
+
+ Disabled Link
+
+
+
+ Link
+
+
+```
+
+With Buttons:
+
+```jsx
+
+
+ Button
+
+
+ Button
+
+
+```
+
+[readme-additional-attributes]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web-react/README.md#additional-attributes
+[readme-escape-hatches]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web-react/README.md#escape-hatches
+[readme-style-props]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web-react/README.md#style-props
+[web-react-unstable-header]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web-react/src/components/UNSTABLE_Header/README.md
diff --git a/packages/web-react/src/components/Navigation/__tests__/Navigation.test.tsx b/packages/web-react/src/components/Navigation/__tests__/Navigation.test.tsx
new file mode 100644
index 0000000000..621ac52c91
--- /dev/null
+++ b/packages/web-react/src/components/Navigation/__tests__/Navigation.test.tsx
@@ -0,0 +1,35 @@
+import '@testing-library/jest-dom';
+import { render, screen } from '@testing-library/react';
+import React from 'react';
+import { classNamePrefixProviderTest } from '../../../../tests/providerTests/classNamePrefixProviderTest';
+import { restPropsTest } from '../../../../tests/providerTests/restPropsTest';
+import { stylePropsTest } from '../../../../tests/providerTests/stylePropsTest';
+import Navigation from '../Navigation';
+
+describe('Navigation', () => {
+ classNamePrefixProviderTest(Navigation, 'Navigation');
+
+ stylePropsTest(Navigation);
+
+ restPropsTest(Navigation, 'nav');
+
+ beforeEach(() => {
+ render(
+
+ Content
+ ,
+ );
+ });
+
+ it('should have default classname', () => {
+ expect(screen.getByRole('navigation')).toHaveClass('Navigation');
+ });
+
+ it('should render list and children', () => {
+ expect(screen.getByRole('list')).toBeInTheDocument();
+ });
+
+ it('should render children', () => {
+ expect(screen.getByText('Content')).toBeInTheDocument();
+ });
+});
diff --git a/packages/web-react/src/components/Navigation/__tests__/NavigationItem.test.tsx b/packages/web-react/src/components/Navigation/__tests__/NavigationItem.test.tsx
new file mode 100644
index 0000000000..2037bdb321
--- /dev/null
+++ b/packages/web-react/src/components/Navigation/__tests__/NavigationItem.test.tsx
@@ -0,0 +1,24 @@
+import '@testing-library/jest-dom';
+import { render, screen } from '@testing-library/react';
+import React from 'react';
+import { restPropsTest } from '../../../../tests/providerTests/restPropsTest';
+import { stylePropsTest } from '../../../../tests/providerTests/stylePropsTest';
+import NavigationItem from '../NavigationItem';
+
+describe('NavigationItem', () => {
+ stylePropsTest(NavigationItem);
+
+ restPropsTest(NavigationItem, 'li');
+
+ it('should have correct role', () => {
+ render(Content );
+
+ expect(screen.getByRole('listitem')).toBeInTheDocument();
+ });
+
+ it('should render children', () => {
+ render(Content );
+
+ expect(screen.getByRole('listitem')).toHaveTextContent('Content');
+ });
+});
diff --git a/packages/web-react/src/components/Navigation/__tests__/NavigationLink.test.tsx b/packages/web-react/src/components/Navigation/__tests__/NavigationLink.test.tsx
new file mode 100644
index 0000000000..6e9a2d5b1f
--- /dev/null
+++ b/packages/web-react/src/components/Navigation/__tests__/NavigationLink.test.tsx
@@ -0,0 +1,49 @@
+import '@testing-library/jest-dom';
+import { render, screen } from '@testing-library/react';
+import React from 'react';
+import { classNamePrefixProviderTest } from '../../../../tests/providerTests/classNamePrefixProviderTest';
+import { restPropsTest } from '../../../../tests/providerTests/restPropsTest';
+import { stylePropsTest } from '../../../../tests/providerTests/stylePropsTest';
+import NavigationLink from '../NavigationLink';
+
+describe('NavigationLink', () => {
+ classNamePrefixProviderTest(NavigationLink, 'NavigationLink');
+
+ stylePropsTest(NavigationLink);
+
+ restPropsTest(NavigationLink, 'a');
+
+ it('should have default classname', () => {
+ render(Content );
+
+ expect(screen.getByRole('link')).toHaveClass('NavigationLink');
+ });
+
+ it('should have selected classname', () => {
+ render(
+
+ Content
+ ,
+ );
+
+ expect(screen.getByRole('link')).toHaveClass('NavigationLink NavigationLink--selected');
+ });
+
+ it('should have disabled classname and correct elementType', () => {
+ render(
+
+ Content
+ ,
+ );
+
+ expect(screen.getByText('Content')).toHaveClass('NavigationLink NavigationLink--disabled');
+ expect(screen.getByText('Content')).toContainHTML('span');
+ expect(screen.queryByRole('link')).not.toBeInTheDocument();
+ });
+
+ it('should render children', () => {
+ render(Content );
+
+ expect(screen.getByText('Content')).toBeInTheDocument();
+ });
+});
diff --git a/packages/web-react/src/components/Navigation/__tests__/useNavigationLinkProps.test.ts b/packages/web-react/src/components/Navigation/__tests__/useNavigationLinkProps.test.ts
new file mode 100644
index 0000000000..2a56d6456c
--- /dev/null
+++ b/packages/web-react/src/components/Navigation/__tests__/useNavigationLinkProps.test.ts
@@ -0,0 +1,97 @@
+import { renderHook } from '@testing-library/react';
+import { SpiritNavigationLinkProps } from '../../../types';
+import { useNavigationLinkProps } from '../useNavigationLinkProps';
+
+describe('useNavigationLinkProps', () => {
+ it('should return defaults props', () => {
+ const props: SpiritNavigationLinkProps = {
+ href: '/',
+ target: '_blank',
+ isSelected: false,
+ isDisabled: false,
+ };
+ const { result } = renderHook(() => useNavigationLinkProps(props));
+
+ expect(result.current).toStrictEqual({
+ navigationLinkProps: {
+ href: '/',
+ rel: undefined,
+ target: '_blank',
+ },
+ });
+ });
+
+ it('should return defaults if element is different from anchor', () => {
+ const props: SpiritNavigationLinkProps<'span'> = {
+ elementType: 'span',
+ href: '/',
+ target: '_blank',
+ isSelected: false,
+ isDisabled: false,
+ };
+ const { result } = renderHook(() => useNavigationLinkProps(props as SpiritNavigationLinkProps));
+
+ expect(result.current).toStrictEqual({
+ navigationLinkProps: {
+ href: undefined,
+ rel: undefined,
+ target: undefined,
+ },
+ });
+ });
+
+ it('should return for isDisabled', () => {
+ const props: SpiritNavigationLinkProps = {
+ href: '/',
+ target: '_blank',
+ isSelected: false,
+ isDisabled: true,
+ };
+ const { result } = renderHook(() => useNavigationLinkProps(props));
+
+ expect(result.current).toStrictEqual({
+ navigationLinkProps: {
+ href: undefined,
+ rel: undefined,
+ target: undefined,
+ },
+ });
+ });
+
+ it('should return for isSelected', () => {
+ const props: SpiritNavigationLinkProps = {
+ href: '/',
+ target: '_blank',
+ isSelected: true,
+ isDisabled: false,
+ };
+ const { result } = renderHook(() => useNavigationLinkProps(props));
+
+ expect(result.current).toStrictEqual({
+ navigationLinkProps: {
+ href: '/',
+ rel: undefined,
+ target: '_blank',
+ },
+ });
+ });
+
+ it('should return for elementType', () => {
+ const props: SpiritNavigationLinkProps<'div'> = {
+ elementType: 'div',
+ href: '/',
+ target: '_blank',
+ isSelected: false,
+ isDisabled: false,
+ };
+ const { result } = renderHook(() => useNavigationLinkProps(props as SpiritNavigationLinkProps));
+
+ expect(result.current).toStrictEqual({
+ navigationLinkProps: {
+ href: undefined,
+ rel: undefined,
+ target: undefined,
+ },
+ });
+ });
+});
diff --git a/packages/web-react/src/components/Navigation/__tests__/useNavigationLinkStyleProps.test.ts b/packages/web-react/src/components/Navigation/__tests__/useNavigationLinkStyleProps.test.ts
new file mode 100644
index 0000000000..d7681c4400
--- /dev/null
+++ b/packages/web-react/src/components/Navigation/__tests__/useNavigationLinkStyleProps.test.ts
@@ -0,0 +1,26 @@
+import { renderHook } from '@testing-library/react';
+import { SpiritNavigationLinkProps } from '../../../types';
+import { useNavigationLinkStyleProps } from '../useNavigationLinkStyleProps';
+
+describe('useNavigationLinkStyleProps', () => {
+ it('should return defaults', () => {
+ const props = {};
+ const { result } = renderHook(() => useNavigationLinkStyleProps(props));
+
+ expect(result.current.classProps).toBe('NavigationLink');
+ });
+
+ it('should return disabled class', () => {
+ const props: SpiritNavigationLinkProps = { isDisabled: true };
+ const { result } = renderHook(() => useNavigationLinkStyleProps(props));
+
+ expect(result.current.classProps).toBe('NavigationLink NavigationLink--disabled');
+ });
+
+ it('should return selected class', () => {
+ const props = { isSelected: true };
+ const { result } = renderHook(() => useNavigationLinkStyleProps(props));
+
+ expect(result.current.classProps).toBe('NavigationLink NavigationLink--selected');
+ });
+});
diff --git a/packages/web-react/src/components/Navigation/__tests__/useNavigationStyleProps.test.ts b/packages/web-react/src/components/Navigation/__tests__/useNavigationStyleProps.test.ts
new file mode 100644
index 0000000000..a1efc2675e
--- /dev/null
+++ b/packages/web-react/src/components/Navigation/__tests__/useNavigationStyleProps.test.ts
@@ -0,0 +1,10 @@
+import { renderHook } from '@testing-library/react';
+import { useNavigationStyleProps } from '../useNavigationStyleProps';
+
+describe('useNavigationStyleProps', () => {
+ it('should return defaults', () => {
+ const { result } = renderHook(() => useNavigationStyleProps());
+
+ expect(result.current.classProps).toBe('Navigation');
+ });
+});
diff --git a/packages/web-react/src/components/Navigation/demo/NavigationButtons.tsx b/packages/web-react/src/components/Navigation/demo/NavigationButtons.tsx
new file mode 100644
index 0000000000..cb0cb2f749
--- /dev/null
+++ b/packages/web-react/src/components/Navigation/demo/NavigationButtons.tsx
@@ -0,0 +1,20 @@
+import React from 'react';
+import { ButtonLink } from '../../ButtonLink';
+import Navigation from '../Navigation';
+import NavigationItem from '../NavigationItem';
+
+const NavigationDefault = () => {
+ return (
+
+
+ Button
+
+
+
+ Button
+
+
+
+ );
+};
+export default NavigationDefault;
diff --git a/packages/web-react/src/components/Navigation/demo/NavigationDefault.tsx b/packages/web-react/src/components/Navigation/demo/NavigationDefault.tsx
new file mode 100644
index 0000000000..9792166066
--- /dev/null
+++ b/packages/web-react/src/components/Navigation/demo/NavigationDefault.tsx
@@ -0,0 +1,12 @@
+import React from 'react';
+import Navigation from '../Navigation';
+import NavigationItem from '../NavigationItem';
+
+const NavigationDefault = () => {
+ return (
+
+ Item
+
+ );
+};
+export default NavigationDefault;
diff --git a/packages/web-react/src/components/Navigation/demo/NavigationLink.tsx b/packages/web-react/src/components/Navigation/demo/NavigationLink.tsx
new file mode 100644
index 0000000000..7ecc70c589
--- /dev/null
+++ b/packages/web-react/src/components/Navigation/demo/NavigationLink.tsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import Navigation from '../Navigation';
+import NavigationItem from '../NavigationItem';
+import NavigationLink from '../NavigationLink';
+
+const NavigationDefault = () => {
+ return (
+
+
+ Link
+
+
+
+ Selected
+
+
+
+
+ Disabled
+
+
+
+ );
+};
+export default NavigationDefault;
diff --git a/packages/web-react/src/components/Navigation/demo/index.tsx b/packages/web-react/src/components/Navigation/demo/index.tsx
new file mode 100644
index 0000000000..01462fe662
--- /dev/null
+++ b/packages/web-react/src/components/Navigation/demo/index.tsx
@@ -0,0 +1,20 @@
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import DocsSection from '../../../../docs/DocsSections';
+import NavigationButtons from './NavigationButtons';
+import NavigationDefault from './NavigationDefault';
+import NavigationLink from './NavigationLink';
+
+ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
+
+
+
+
+
+
+
+
+
+
+ ,
+);
diff --git a/packages/web-react/src/components/Navigation/index.html b/packages/web-react/src/components/Navigation/index.html
new file mode 100644
index 0000000000..59b5d4e1c8
--- /dev/null
+++ b/packages/web-react/src/components/Navigation/index.html
@@ -0,0 +1 @@
+{{> web-react/demo title="Navigation" parentPageName="Components" }}
diff --git a/packages/web-react/src/components/Navigation/index.ts b/packages/web-react/src/components/Navigation/index.ts
new file mode 100644
index 0000000000..8cf2651bce
--- /dev/null
+++ b/packages/web-react/src/components/Navigation/index.ts
@@ -0,0 +1,8 @@
+'use client';
+
+export { default as Navigation } from './Navigation';
+export { default as NavigationItem } from './NavigationItem';
+export { default as NavigationLink } from './NavigationLink';
+export * from './useNavigationStyleProps';
+export * from './useNavigationLinkProps';
+export * from './useNavigationLinkStyleProps';
diff --git a/packages/web-react/src/components/Navigation/stories/Navigation.stories.tsx b/packages/web-react/src/components/Navigation/stories/Navigation.stories.tsx
new file mode 100644
index 0000000000..123f16c34a
--- /dev/null
+++ b/packages/web-react/src/components/Navigation/stories/Navigation.stories.tsx
@@ -0,0 +1,43 @@
+import { Markdown } from '@storybook/blocks';
+import type { Meta, StoryObj } from '@storybook/react';
+import React from 'react';
+import Navigation from '../Navigation';
+import NavigationItem from '../NavigationItem';
+import NavigationLink from '../NavigationLink';
+import ReadMe from '../README.md';
+
+const meta: Meta = {
+ title: 'Components/Navigation',
+ component: Navigation,
+ parameters: {
+ docs: {
+ page: () => {ReadMe} ,
+ },
+ },
+ argTypes: {
+ children: {
+ control: 'object',
+ },
+ },
+ args: {
+ children: (
+ <>
+
+
+ Home
+
+
+
+ Not Home
+
+ >
+ ),
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Playground: Story = {
+ name: 'Navigation',
+};
diff --git a/packages/web-react/src/components/Navigation/stories/NavigationItem.stories.tsx b/packages/web-react/src/components/Navigation/stories/NavigationItem.stories.tsx
new file mode 100644
index 0000000000..60ec676e0a
--- /dev/null
+++ b/packages/web-react/src/components/Navigation/stories/NavigationItem.stories.tsx
@@ -0,0 +1,31 @@
+import { Markdown } from '@storybook/blocks';
+import type { Meta, StoryObj } from '@storybook/react';
+import React from 'react';
+import NavigationItem from '../NavigationItem';
+import NavigationLink from '../NavigationLink';
+import ReadMe from '../README.md';
+
+const meta: Meta = {
+ title: 'Components/Navigation',
+ component: NavigationItem,
+ parameters: {
+ docs: {
+ page: () => {ReadMe} ,
+ },
+ },
+ args: {
+ children: Link ,
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const NavigationItemPlayground: Story = {
+ name: 'NavigationItem',
+ render: (args) => (
+
+ ),
+};
diff --git a/packages/web-react/src/components/Navigation/stories/NavigationLink.stories.tsx b/packages/web-react/src/components/Navigation/stories/NavigationLink.stories.tsx
new file mode 100644
index 0000000000..5c531ee0da
--- /dev/null
+++ b/packages/web-react/src/components/Navigation/stories/NavigationLink.stories.tsx
@@ -0,0 +1,41 @@
+import { Markdown } from '@storybook/blocks';
+import type { Meta, StoryObj } from '@storybook/react';
+import React from 'react';
+import NavigationLink from '../NavigationLink';
+import ReadMe from '../README.md';
+
+const meta: Meta = {
+ title: 'Components/Navigation',
+ component: NavigationLink,
+ parameters: {
+ docs: {
+ page: () => {ReadMe} ,
+ },
+ },
+ argTypes: {
+ isDisabled: {
+ control: 'boolean',
+ table: {
+ defaultValue: { summary: 'false' },
+ },
+ },
+ isSelected: {
+ control: 'boolean',
+ table: {
+ defaultValue: { summary: 'false' },
+ },
+ },
+ },
+ args: {
+ children: 'Link',
+ isDisabled: false,
+ isSelected: false,
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const NavigationLinkPlayground: Story = {
+ name: 'NavigationLink',
+};
diff --git a/packages/web-react/src/components/Navigation/useNavigationLinkProps.ts b/packages/web-react/src/components/Navigation/useNavigationLinkProps.ts
new file mode 100644
index 0000000000..30a8ea89dd
--- /dev/null
+++ b/packages/web-react/src/components/Navigation/useNavigationLinkProps.ts
@@ -0,0 +1,21 @@
+import { SpiritNavigationLinkProps } from '../../types';
+
+export type UseNavigationLinkProps = Partial;
+
+export type UseNavigationLinkReturn = {
+ navigationLinkProps: UseNavigationLinkProps;
+};
+
+export const useNavigationLinkProps = (props: UseNavigationLinkProps): UseNavigationLinkReturn => {
+ const { elementType = 'a', isDisabled, href, target, rel } = props;
+
+ const navigationLinkProps: Partial = {
+ href: elementType === 'a' && !isDisabled ? href : undefined,
+ target: elementType === 'a' && !isDisabled ? target : undefined,
+ rel: elementType === 'a' ? rel : undefined,
+ };
+
+ return {
+ navigationLinkProps,
+ };
+};
diff --git a/packages/web-react/src/components/Navigation/useNavigationLinkStyleProps.ts b/packages/web-react/src/components/Navigation/useNavigationLinkStyleProps.ts
new file mode 100644
index 0000000000..bdd2cca267
--- /dev/null
+++ b/packages/web-react/src/components/Navigation/useNavigationLinkStyleProps.ts
@@ -0,0 +1,31 @@
+import classNames from 'classnames';
+import { ElementType } from 'react';
+import { useClassNamePrefix } from '../../hooks';
+import { LinkProps, SpiritNavigationLinkProps } from '../../types';
+
+export interface NavigationLinkStyles {
+ /** className props */
+ classProps: string | null;
+ /** props to be passed to the input element */
+ props: Partial>;
+}
+
+export function useNavigationLinkStyleProps(
+ props: SpiritNavigationLinkProps,
+): NavigationLinkStyles {
+ const { isDisabled, isSelected, ...restProps } = props;
+
+ const navigationLinkClass = useClassNamePrefix('NavigationLink');
+ const navigationLinkDisabledClass = `${navigationLinkClass}--disabled`;
+ const navigationLinkSelectedClass = `${navigationLinkClass}--selected`;
+
+ const className = classNames(navigationLinkClass, {
+ [navigationLinkDisabledClass]: isDisabled,
+ [navigationLinkSelectedClass]: isSelected,
+ });
+
+ return {
+ classProps: className,
+ props: restProps,
+ };
+}
diff --git a/packages/web-react/src/components/Navigation/useNavigationStyleProps.ts b/packages/web-react/src/components/Navigation/useNavigationStyleProps.ts
new file mode 100644
index 0000000000..608f5492f7
--- /dev/null
+++ b/packages/web-react/src/components/Navigation/useNavigationStyleProps.ts
@@ -0,0 +1,13 @@
+import { useClassNamePrefix } from '../../hooks';
+
+export interface NavigationStyles {
+ classProps: string;
+}
+
+export const useNavigationStyleProps = () => {
+ const navigationClass = useClassNamePrefix('Navigation');
+
+ return {
+ classProps: navigationClass,
+ };
+};
diff --git a/packages/web-react/src/components/UNSTABLE_Header/README.md b/packages/web-react/src/components/UNSTABLE_Header/README.md
index 2a37500ab9..b4dc55c6e4 100644
--- a/packages/web-react/src/components/UNSTABLE_Header/README.md
+++ b/packages/web-react/src/components/UNSTABLE_Header/README.md
@@ -20,7 +20,7 @@ import { UNSTABLE_Header } from '@lmc-eu/spirit-web-react';
{/* Content go here */} ;
```
-It also sets CSS variable for the Header height which can be used in other nested components.
+It also sets CSS variable for the Header height which can be used by nested components.
### API
@@ -36,9 +36,6 @@ and [escape hatches][readme-escape-hatches].
The `UNSTABLE_HeaderLogo` component is a container for the logo.
-Without any modifier, Header is ready to contain necessary blocks in a classic
-left-to-right layout (in LTR documents).
-
```jsx
import { UNSTABLE_HeaderLogo } from '@lmc-eu/spirit-web-react';
@@ -80,7 +77,7 @@ Use [`Container`][web-react-container] and [`Flex`][web-react-flex] components t
```
-This way you can modify the layout of the Header content easily and modify it how you need.
+This way you can easily modify the layout of the Header content.
For example you can make the content centered by setting the `Flex` alignment properties to center.
@@ -94,7 +91,7 @@ For example you can make the content centered by setting the `Flex` alignment pr
```
-Or you can make modify gaps between the content by setting the `Flex` spacing property.
+Or you can modify the gaps between the content by setting the `Flex` `spacing` property.
```jsx
diff --git a/packages/web-react/src/components/UNSTABLE_Header/useUnstableHeaderStyleProps.ts b/packages/web-react/src/components/UNSTABLE_Header/useUnstableHeaderStyleProps.ts
index 247d7b4608..ec38f218e7 100644
--- a/packages/web-react/src/components/UNSTABLE_Header/useUnstableHeaderStyleProps.ts
+++ b/packages/web-react/src/components/UNSTABLE_Header/useUnstableHeaderStyleProps.ts
@@ -1,5 +1,5 @@
import { useClassNamePrefix } from '../../hooks';
-import { SpiritHeaderProps } from './UNSTABLE_Header';
+import { SpiritHeaderProps } from '../../types';
export interface HeaderStyles {
classProps: {
diff --git a/packages/web-react/src/components/index.ts b/packages/web-react/src/components/index.ts
index 857be0d09b..f9b932fa78 100644
--- a/packages/web-react/src/components/index.ts
+++ b/packages/web-react/src/components/index.ts
@@ -22,6 +22,7 @@ export * from './Icon';
export * from './Item';
export * from './Link';
export * from './Modal';
+export * from './Navigation';
export * from './NoSsr';
export * from './Pagination';
export * from './PartnerLogo';
@@ -42,6 +43,7 @@ export * from './Toast';
export * from './Tooltip';
export * from './UNSTABLE_ActionLayout';
export * from './UNSTABLE_Avatar';
+export * from './UNSTABLE_Header';
export * from './UNSTABLE_EmptyState';
export * from './UNSTABLE_Slider';
export * from './UNSTABLE_Toggle';
diff --git a/packages/web-react/src/types/index.ts b/packages/web-react/src/types/index.ts
index 84dcbe757b..d99aaf4fb1 100644
--- a/packages/web-react/src/types/index.ts
+++ b/packages/web-react/src/types/index.ts
@@ -20,6 +20,7 @@ export * from './item';
export * from './label';
export * from './link';
export * from './modal';
+export * from './navigation';
export * from './pagination';
export * from './pill';
export * from './radio';
diff --git a/packages/web-react/src/types/navigation.ts b/packages/web-react/src/types/navigation.ts
new file mode 100644
index 0000000000..2c3f9c490e
--- /dev/null
+++ b/packages/web-react/src/types/navigation.ts
@@ -0,0 +1,42 @@
+import { ElementType, ReactElement } from 'react';
+import { NavigationItem } from '../components';
+import { LinkTarget } from './link';
+import {
+ AriaLabelingProps,
+ ChildrenProps,
+ SpiritPolymorphicElementPropsWithRef,
+ StyleProps,
+ TransferProps,
+} from './shared';
+
+export interface NavigationLinkBaseProps extends ChildrenProps, StyleProps, AriaLabelingProps, TransferProps {
+ /** NavigationLink's href attribute */
+ href?: string;
+ /** Whether is the NavigationLink disabled */
+ isDisabled?: boolean;
+ /** Whether is the NavigationLink selected */
+ isSelected?: boolean;
+ /** NavigationLink's target attribute */
+ target?: LinkTarget;
+}
+
+export type NavigationLinkProps = {
+ /**
+ * The HTML element or React element used to render the button, e.g. 'div', 'a', or `RouterLink`.
+ *
+ * @default 'a'
+ */
+ elementType?: E;
+} & NavigationLinkBaseProps;
+
+export interface SpiritNavigationItemProps extends ChildrenProps, StyleProps {}
+
+export type SpiritNavigationLinkProps = NavigationLinkProps &
+ SpiritPolymorphicElementPropsWithRef>;
+
+export interface SpiritNavigationProps extends StyleProps, AriaLabelingProps {
+ children:
+ | ReactElement
+ | ReactElement
+ | Array | ReactElement>;
+}
diff --git a/packages/web-react/src/types/unstableHeader.ts b/packages/web-react/src/types/unstableHeader.ts
index bf3186a998..f970e0592f 100644
--- a/packages/web-react/src/types/unstableHeader.ts
+++ b/packages/web-react/src/types/unstableHeader.ts
@@ -1,6 +1,6 @@
-import { ChildrenProps, SpiritPolymorphicElementPropsWithRef, StyleProps, TransferProps } from './shared';
-import { LinkTarget } from './link';
import { ElementType } from 'react';
+import { LinkTarget } from './link';
+import { ChildrenProps, SpiritPolymorphicElementPropsWithRef, StyleProps, TransferProps } from './shared';
export interface HeaderLogoBaseProps extends ChildrenProps, StyleProps, TransferProps {
/** Header's href attribute */
diff --git a/tests/e2e/demo-homepages.spec.ts-snapshots/web-react-chromium-linux.png b/tests/e2e/demo-homepages.spec.ts-snapshots/web-react-chromium-linux.png
index b30023dc88..07611c423a 100644
Binary files a/tests/e2e/demo-homepages.spec.ts-snapshots/web-react-chromium-linux.png and b/tests/e2e/demo-homepages.spec.ts-snapshots/web-react-chromium-linux.png differ