diff --git a/src/components/Stepper/README-ru.md b/src/components/Stepper/README-ru.md
new file mode 100644
index 000000000..7167f3277
--- /dev/null
+++ b/src/components/Stepper/README-ru.md
@@ -0,0 +1,227 @@
+
+
+# Stepper
+
+
+
+```tsx
+import {Stepper} from '@gravity-ui/uikit';
+```
+
+`Stepper` - это компонент, который отображает прогресс при помощи последовательности пронумерованных шагов. Компонент обеспечивает возможность использования wizard-like процессов работы.
+
+## Example
+
+
+
+```jsx
+
+ Step 1
+ Step 2
+ Step 3
+ Step 4 with very long title
+
+```
+
+
+
+
+
+
+
+### Interactive items
+
+Используйте `onUpdate` и `value` параметры вместе с кастомным состоянием для управления шагами
+
+
+
+```jsx
+const [value, setValue] = React.useState();
+
+return (
+
+ Step 1
+ Step 2
+ Step 3
+ Step 4 with very long title
+
+);
+```
+
+
+
+
+
+
+
+### Different views
+
+
+
+```jsx
+
+ Step 1
+ Step 2
+ Step 3
+ Step 4
+
+```
+
+
+
+
+
+
+
+### Different sizes
+
+
+
+```jsx
+
+
+ Step 1
+ Step 2
+ Step 3
+
+
+
+ Step 1
+ Step 2
+ Step 3
+
+
+
+ Step 1
+ Step 2
+ Step 3
+
+
+```
+
+
+
+
+
+
+
+### Disabled steps
+
+
+
+```jsx
+
+ Step 1
+ Step 2
+ Step 3
+ Step 4 with very long title
+
+```
+
+
+
+
+
+
+
+### Custom icons
+
+
+
+```jsx
+
+ }>Step 1
+ }>
+ Step 2
+
+ }>
+ Step 3
+
+ Step 4 with very long title
+
+```
+
+
+
+
+
+
+
+### Custom step separator
+
+
+
+```jsx
+const Separator = () => {
+ return {'->'};
+};
+
+}>
+ Step 1
+ Step 2
+ Step 3
+ Step 4 with very long title
+;
+```
+
+
+
+
+
+
+
+### Step with floating element
+
+
+
+```jsx
+}>
+
+ Step 1
+
+ Step 2
+ Step 3
+ Step 4 with very long title
+
+```
+
+
+
+
+
+
+
+## Properties
+
+| Name | Description | Type | Default |
+| :--------------- | :---------------------------------------------------------------------------------- | :------------------------------------- | :------ |
+| children | Дочерние элементы степера. | `React.ReactElement` | |
+| size | Задает размер степа. | `"s"` `"m"` `"l"` | `"s"` |
+| value | Текущий выбранный идентификатор степа. | `number` `string` | |
+| onUpdate | Функция для обновления текущего выбранного элемента. | `Function` | |
+| qa | `data-qa` HTML атрибут, используется для тестирования. | `string` | |
+| separator | Кастомная нода-разделитель степов. | `React.ReactNode` | |
+| className | CSS имя класса Step контейнера. | `string` | |
+| style | Задает инлайн-стили Step контейнера. | `CSSProperties` | |
+| aria-label | Определяет строковое значение, используемое в качестве метки для текущего элемента. | `string` | |
+| aria-labelledby | Определяет элементы, используемые в качестве метки для текущего элемента. | `string` | |
+| aria-describedby | Определяет элементы, описывающие объект. | `string` | |
+
+### StepperItemProps
+
+| Name | Description | Type | Default |
+| :-------- | :----------------------------------------------------------------------- | :----------------------------- | :------- |
+| id | Идентификатора степа. Если не передан, берется значения индекса массива. | `string` `number` | |
+| view | Внешний вид степа. | `"idle"` `"error"` `"success"` | `"idle"` |
+| children | Внутреннее содержимое степа. | `React.Node` | |
+| disabled | Устанавливает заблокированное состояние для степа. | `boolean` | |
+| icon | Задает кастомную иконка степа | `SVGIconData` | |
+| onClick | Обработчик клика на степ | `React.MouseEventHandler` | |
+| className | CSS class name элемента | `string` | |
+
+### CSS API
+
+| Name | Description |
+| :-------------------------------- | :--------------------------------------------- |
+| `--g-stepper-gap` | Расстояние между степами и разделителем. |
+| `--g-stepper-item-text-max-width` | Максимальная ширина текстового контента степа. |
diff --git a/src/components/Stepper/README.md b/src/components/Stepper/README.md
new file mode 100644
index 000000000..141ca3928
--- /dev/null
+++ b/src/components/Stepper/README.md
@@ -0,0 +1,229 @@
+
+
+# Stepper
+
+
+
+```tsx
+import {Stepper} from '@gravity-ui/uikit';
+```
+
+`Stepper` convey progress through numbered steps. It provides a wizard-like workflow.Steppers display progress through a sequence of logical and numbered steps.
+
+## Example
+
+
+
+```jsx
+
+ Step 1
+ Step 2
+ Step 3
+ Step 4 with very long title
+
+```
+
+
+
+
+
+
+
+### Interactive items
+
+Use `onUpdate` and `value` props with custom state to manipulate steps
+
+
+
+```jsx
+const [value, setValue] = React.useState();
+
+return (
+
+ Step 1
+ Step 2
+ Step 3
+ Step 4 with very long title
+
+);
+```
+
+
+
+
+
+
+
+### Different views
+
+
+
+```jsx
+
+ Step 1
+ Step 2
+ Step 3
+ Step 4
+
+```
+
+
+
+
+
+
+
+### Different sizes
+
+
+
+```jsx
+
+
+ Step 1
+ Step 2
+ Step 3
+
+
+
+ Step 1
+ Step 2
+ Step 3
+
+
+
+ Step 1
+ Step 2
+ Step 3
+
+
+```
+
+
+
+
+
+
+
+### Disabled steps
+
+
+
+```jsx
+
+ Step 1
+ Step 2
+ Step 3
+ Step 4 with very long title
+
+```
+
+
+
+
+
+
+
+### Custom icons
+
+
+
+```jsx
+
+ }>Step 1
+ }>
+ Step 2
+
+ }>
+ Step 3
+
+ Step 4 with very long title
+
+```
+
+
+
+
+
+
+
+### Custom step separator
+
+
+
+```jsx
+const Separator = () => {
+ return {'->'};
+};
+
+}>
+ Step 1
+ Step 2
+ Step 3
+ Step 4 with very long title
+;
+```
+
+
+
+
+
+
+
+
+
+### Step with floating element
+
+
+
+```jsx
+}>
+
+ Step 1
+
+ Step 2
+ Step 3
+ Step 4 with very long title
+
+```
+
+
+
+
+
+
+
+## Properties
+
+| Name | Description | Type | Default |
+| :--------------- | :-------------------------------------------------------- | :------------------------------------- | :------ |
+| children | Stepper items. | `React.ReactElement` | |
+| size | Set the `Step` size. | `"s"` `"m"` `"l"` | `"s"` |
+| value | Current selected `Step` id. | `number` `string` | |
+| onUpdate | function for change current `Step`. | `Function` | |
+| qa | `data-qa` HTML attribute, used for testing. | `string` | |
+| separator | Custom separator node. | `React.ReactNode` | |
+| className | CSS class name for the Steps container. | `string` | |
+| style | Sets the inline style for the Steps container. | `CSSProperties` | |
+| aria-label | Defines a string value that labels the current element. | `string` | |
+| aria-labelledby | Identifies the element(s) that label the current element. | `string` | |
+| aria-describedby | Identifies the element(s) that describe the object. | `string` | |
+
+### StepperItemProps
+
+| Name | Description | Type | Default |
+| :-------- | :------------------------------------------------ | :----------------------------- | :------- |
+| id | Set `Step` id. Index of array element as default. | `string` `number` | |
+| view | Set `Step` view. | `"idle"` `"error"` `"success"` | `"idle"` |
+| children | `Step` content. | `React.Node` | |
+| disabled | Determines whether `Step` is disable. | `boolean` | |
+| icon | Custom icon node. | `SVGIconData` | |
+| onClick | Step click handler. | `React.MouseEventHandler` | |
+| className | CSS class name for the element. | `string` | |
+
+### CSS API
+
+| Name | Description |
+| :-------------------------------- | :------------------------------------ |
+| `--g-stepper-gap` | Gap between step items and separator. |
+| `--g-stepper-item-text-max-width` | Step item text max-width. |
diff --git a/src/components/Stepper/Stepper.scss b/src/components/Stepper/Stepper.scss
new file mode 100644
index 000000000..08f3c1dab
--- /dev/null
+++ b/src/components/Stepper/Stepper.scss
@@ -0,0 +1,70 @@
+@use '../variables';
+@use '../../../styles/mixins';
+
+$block: '.#{variables.$ns}stepper';
+
+#{$block} {
+ --_--text-max-width: 150px;
+ --_--step-gap: var(--g-stepper-gap, var(--g-spacing-2));
+
+ list-style: none;
+ display: flex;
+ gap: var(--_--step-gap);
+
+ &__list-item {
+ display: flex;
+ flex-wrap: nowrap;
+ gap: var(--_--step-gap);
+ align-items: center;
+ }
+
+ &__item {
+ &_selected:not(&_disabled) {
+ border-color: var(--g-color-line-info);
+ }
+
+ &_disabled {
+ cursor: default;
+
+ #{$block}__item-text {
+ color: var(--g-color-text-hint);
+ }
+ }
+ }
+
+ &__item-text {
+ display: inline-block;
+ vertical-align: middle;
+
+ width: 100%;
+ max-width: var(--g-stepper-item-text-max-width, var(--_--text-max-width));
+ color: var(--g-color-text-primary);
+
+ @include mixins.overflow-ellipsis();
+ }
+
+ &__item-icon {
+ width: 16px;
+ height: 16px;
+
+ &_view {
+ &_idle {
+ color: var(--g-color-text-secondary);
+ }
+
+ &_error {
+ color: var(--g-color-text-danger);
+ }
+
+ &_success {
+ color: var(--g-color-text-positive);
+ }
+ }
+ }
+
+ &__separator {
+ display: flex;
+ align-items: center;
+ color: var(--g-color-text-secondary);
+ }
+}
diff --git a/src/components/Stepper/Stepper.tsx b/src/components/Stepper/Stepper.tsx
new file mode 100644
index 000000000..8e8037779
--- /dev/null
+++ b/src/components/Stepper/Stepper.tsx
@@ -0,0 +1,58 @@
+'use client';
+
+import * as React from 'react';
+
+import type {AriaLabelingProps, DOMProps, QAProps} from '../types';
+import {filterDOMProps} from '../utils/filterDOMProps';
+
+import {StepperItem} from './StepperItem';
+import {StepperSeparator} from './StepperSeparator';
+import {StepperContext} from './context';
+import type {StepperSize} from './types';
+import {b} from './utils';
+
+import './Stepper.scss';
+
+export interface StepperProps extends DOMProps, AriaLabelingProps, QAProps {
+ children: React.ReactElement | React.ReactElement[];
+ value?: number | string;
+ onUpdate?: (id?: number | string) => void;
+ size?: StepperSize;
+ separator?: React.ReactNode;
+}
+
+export const Stepper = (props: StepperProps) => {
+ const {children, value, size = 's', className, onUpdate, separator} = props;
+
+ const stepItems = React.useMemo(() => {
+ return React.Children.map(children, (child, index) => {
+ const itemId = child.props?.id || index;
+ const clonedChild = React.cloneElement(child, {id: itemId});
+
+ return (
+
+ {clonedChild}
+ {Boolean(index !== React.Children.count(children) - 1) && (
+
+ )}
+
+ );
+ });
+ }, [children, separator]);
+
+ return (
+
+
+ {stepItems}
+
+
+ );
+};
+
+Stepper.Item = StepperItem;
+Stepper.displayName = 'Stepper';
diff --git a/src/components/Stepper/StepperItem.tsx b/src/components/Stepper/StepperItem.tsx
new file mode 100644
index 000000000..d3b42bece
--- /dev/null
+++ b/src/components/Stepper/StepperItem.tsx
@@ -0,0 +1,85 @@
+import * as React from 'react';
+
+import {CircleCheck, CircleDashed, CircleExclamation} from '@gravity-ui/icons';
+
+import {Button} from '../Button';
+import type {ButtonButtonProps} from '../Button';
+import {Icon} from '../Icon';
+import type {SVGIconData} from '../Icon/types';
+import {Text} from '../Text';
+
+import {useStepperContext} from './context';
+import type {StepperItemView} from './types';
+import {b} from './utils';
+
+export type StepperItemProps = Omit & {
+ id?: string | number;
+ children: React.ReactNode;
+ view?: StepperItemView;
+ disabled?: boolean;
+ icon?: SVGIconData;
+ onClick?: (event: React.MouseEvent) => void;
+ className?: string;
+};
+
+export const StepperItem = React.forwardRef((props, ref) => {
+ const {
+ id,
+ children,
+ view = 'idle',
+ disabled = false,
+ className,
+ icon: customIcon,
+ ...restButtonProps
+ } = props;
+
+ const {onUpdate, value, size} = useStepperContext();
+
+ const onClick = (e: React.MouseEvent) => {
+ props.onClick?.(e);
+
+ onUpdate?.(id);
+ };
+
+ const icon = React.useMemo(() => {
+ if (customIcon) {
+ return customIcon;
+ }
+
+ switch (view) {
+ case 'idle': {
+ return CircleDashed;
+ }
+ case 'error': {
+ return CircleExclamation;
+ }
+ case 'success': {
+ return CircleCheck;
+ }
+ default: {
+ return CircleDashed;
+ }
+ }
+ }, [view, customIcon]);
+
+ const selectedItem = id === undefined ? false : id === value;
+
+ return (
+
+ );
+});
+
+StepperItem.displayName = 'StepperItem';
diff --git a/src/components/Stepper/StepperSeparator.tsx b/src/components/Stepper/StepperSeparator.tsx
new file mode 100644
index 000000000..01c966615
--- /dev/null
+++ b/src/components/Stepper/StepperSeparator.tsx
@@ -0,0 +1,19 @@
+import {ChevronLeft, ChevronRight} from '@gravity-ui/icons';
+
+import {Icon} from '../Icon';
+import {useDirection} from '../theme';
+
+import {b} from './utils';
+
+type StepperSeparatorProps = {
+ separator?: React.ReactNode;
+};
+
+export const StepperSeparator = ({separator}: StepperSeparatorProps) => {
+ const direction = useDirection();
+ return (
+
+ {separator ?? }
+
+ );
+};
diff --git a/src/components/Stepper/__stories__/Docs.mdx b/src/components/Stepper/__stories__/Docs.mdx
new file mode 100644
index 000000000..ed08c8aef
--- /dev/null
+++ b/src/components/Stepper/__stories__/Docs.mdx
@@ -0,0 +1,47 @@
+import {
+ Meta,
+ Markdown,
+ Canvas,
+ AnchorMdx,
+ CodeOrSourceMdx,
+ HeadersMdx,
+} from '@storybook/addon-docs';
+import * as Stories from './Stepper.stories';
+import Readme from '../README.md?raw';
+
+export const StepperDefault = () => ;
+export const StepperSize = () => ;
+export const StepperView = () => ;
+export const StepperCustomIcons = () => ;
+export const StepperCustomSeparator = () => (
+
+);
+export const StepperDisabled = () => ;
+export const StepperWithFloatingElements = () => (
+
+);
+export const StepperInteractiveShowcase = () => (
+
+);
+
+
+
+
+ {Readme}
+
diff --git a/src/components/Stepper/__stories__/Stepper.stories.tsx b/src/components/Stepper/__stories__/Stepper.stories.tsx
new file mode 100644
index 000000000..1d5773e14
--- /dev/null
+++ b/src/components/Stepper/__stories__/Stepper.stories.tsx
@@ -0,0 +1,133 @@
+import {Cloud, CreditCard, Rocket} from '@gravity-ui/icons';
+import type {Meta, StoryObj} from '@storybook/react';
+
+import {Text} from '../../Text';
+import {Tooltip} from '../../Tooltip';
+import {Stepper} from '../Stepper';
+
+import {StepperInteractiveShowcase, StepperSizeShowcase} from './StepperShowcase';
+
+export default {
+ title: 'Components/Navigation/Stepper',
+ component: Stepper,
+ parameters: {
+ a11y: {
+ element: '#storybook-root',
+ config: {
+ rules: [
+ {
+ id: 'color-contrast',
+ enabled: false, // actual color contrast may differ in particular usage
+ },
+ {
+ id: 'duplicate-id',
+ enabled: false,
+ selector: 'defs', // one may use same id in different
+ },
+ ],
+ },
+ },
+ },
+} as Meta;
+
+type Story = StoryObj;
+
+export const Default = {
+ render: (args) => {
+ return (
+
+ Step 1
+ Step 2
+ Step 3
+ Step 4 with very long title
+
+ );
+ },
+} satisfies Story;
+
+export const View = {
+ render: (args) => {
+ return (
+
+ Step 1
+ Step 2
+ Step 3
+ Step 4 with very long title
+
+ );
+ },
+} satisfies Story;
+
+export const Size = {
+ render: () => {
+ return ;
+ },
+} satisfies Story;
+
+export const Disabled = {
+ render: (args) => {
+ return (
+
+ Step 1
+ Step 2
+ Step 3
+ Step 4 with very long title
+
+ );
+ },
+} satisfies Story;
+
+export const CustomIcons = {
+ render: (args) => {
+ return (
+
+ Step 1
+
+ Step 2
+
+
+ Step 3
+
+ Step 4 with very long title
+
+ );
+ },
+} satisfies Story;
+
+const Separator = () => {
+ return {'->'};
+};
+
+export const CustomSeparator = {
+ render: (args) => {
+ return (
+ }>
+ Step 1
+ Step 2
+ Step 3
+ Step 4 with very long title
+
+ );
+ },
+} satisfies Story;
+
+export const InteractiveShowcase = {
+ render: (args) => {
+ return ;
+ },
+} satisfies Story;
+
+export const WithFloatingElements = {
+ render: (args) => {
+ return (
+ }>
+
+ Step 1
+
+ Step 2
+ Step 3
+ Step 4 with very long title
+
+ );
+ },
+} satisfies Story;
diff --git a/src/components/Stepper/__stories__/StepperShowcase.tsx b/src/components/Stepper/__stories__/StepperShowcase.tsx
new file mode 100644
index 000000000..bd8d8bdbb
--- /dev/null
+++ b/src/components/Stepper/__stories__/StepperShowcase.tsx
@@ -0,0 +1,42 @@
+import * as React from 'react';
+
+import {Flex} from '../../layout/Flex/Flex';
+import {Stepper} from '../Stepper';
+import type {StepperProps} from '../Stepper';
+
+export const StepperInteractiveShowcase = (props: StepperProps) => {
+ const [value, setValue] = React.useState(0);
+
+ return (
+
+ Step 1
+ Step 2
+ Step 3
+ Step 4 with very long title
+
+ );
+};
+
+export const StepperSizeShowcase = () => {
+ return (
+
+
+ Step 1
+ Step 2
+ Step 3
+
+
+
+ Step 1
+ Step 2
+ Step 3
+
+
+
+ Step 1
+ Step 2
+ Step 3
+
+
+ );
+};
diff --git a/src/components/Stepper/context.ts b/src/components/Stepper/context.ts
new file mode 100644
index 000000000..7d1f54807
--- /dev/null
+++ b/src/components/Stepper/context.ts
@@ -0,0 +1,17 @@
+import * as React from 'react';
+
+import type {StepperProps} from './Stepper';
+
+export type StepperContextProps = Pick;
+
+export const StepperContext = React.createContext({
+ size: 'm',
+ onUpdate: undefined,
+ value: undefined,
+});
+
+export const useStepperContext = () => {
+ const data = React.useContext(StepperContext);
+
+ return data;
+};
diff --git a/src/components/Stepper/index.ts b/src/components/Stepper/index.ts
new file mode 100644
index 000000000..f050967a4
--- /dev/null
+++ b/src/components/Stepper/index.ts
@@ -0,0 +1,3 @@
+export * from './Stepper';
+
+export * from './types';
diff --git a/src/components/Stepper/types.ts b/src/components/Stepper/types.ts
new file mode 100644
index 000000000..c864a9163
--- /dev/null
+++ b/src/components/Stepper/types.ts
@@ -0,0 +1,3 @@
+export type StepperItemView = 'idle' | 'error' | 'success';
+
+export type StepperSize = 's' | 'm' | 'l';
diff --git a/src/components/Stepper/utils.ts b/src/components/Stepper/utils.ts
new file mode 100644
index 000000000..89f1d58b9
--- /dev/null
+++ b/src/components/Stepper/utils.ts
@@ -0,0 +1,3 @@
+import {block} from '../utils/cn';
+
+export const b = block('stepper');