+ );
+}
diff --git a/src/components/DefinitionList/README.md b/src/components/DefinitionList/README.md
new file mode 100644
index 00000000..cd0bbf64
--- /dev/null
+++ b/src/components/DefinitionList/README.md
@@ -0,0 +1,44 @@
+## DefinitionList
+
+The component to display definition list with term and definition separated by dots.
+
+### PropTypes
+
+| Property | Type | Required | Default | Description |
+| :-------------- | :---------------------- | :-------: | :------ | :----------------------------------------------------------- |
+| [items](#items) | `DefinitionListItem[]` | yes | | Items of the list |
+| responsive | `boolean` | | | If set to `true` list will take 100% width of its parent |
+| nameMaxWidth | `number` | | | Maximum width of term |
+| contentMaxWidth | `number \| 'auto'` | | 'auto' | Maximum width of definition |
+| className | `string` | | | Class name for the list container |
+| itemClassName | `string` | | | Class name for the list item |
+| copyPosition | `'inside' \| 'outside'` | 'outside' | | If set to `inside`, copy icon will be placed over definition |
+
+#### Items
+
+Configuration for list items
+
+| Property | Type | Required | Default | Description |
+| ------------- | ---------------------------- | -------- | ------- | -------------------------------------------------------------- |
+| name | `ReactNode` | true | | Term |
+| multilineName | `boolean` | | | If set, term will be multiline |
+| content | `ReactNode` | | | Definition |
+| contentTitle | `string` | | | Title for definition. If not set, `content` value will be used |
+| nameTitle | `string` | | | Title for term. If not set, `name` value will be used |
+| copyText | `string` | | | If set, it will be shown icon for copy this text |
+| note | `string \| HelpPopoverProps` | | | If set, HelpPopover will be shown next to term |
+
+```jsx
+value with copy,
+ copyText: 'value',
+ },
+ {name: 'Empty value with copy', copyText: 'nothing to copy'},
+ ]}
+ nameMaxWidth="100"
+ contentMaxWidth="100"
+/>
+```
diff --git a/src/components/DefinitionList/__stories__/DefinitionList.stories.tsx b/src/components/DefinitionList/__stories__/DefinitionList.stories.tsx
new file mode 100644
index 00000000..53e4597c
--- /dev/null
+++ b/src/components/DefinitionList/__stories__/DefinitionList.stories.tsx
@@ -0,0 +1,146 @@
+import React from 'react';
+
+import {Label, Link, User} from '@gravity-ui/uikit';
+import {Meta, StoryFn} from '@storybook/react';
+
+import {DefinitionList, DefinitionListItem, DefinitionListProps} from '../DefinitionList';
+
+const items: DefinitionListItem[] = [
+ {name: String value, content: 'value'},
+ {
+ name: (
+
+ ),
+ content: 'value',
+ note: 'This is avatar',
+ },
+ {name: 'Number value', content: 2},
+ {name: 'Node value', content: value},
+ {name: 'Empty value'},
+ {name: 'String value with copy', content: 'value', copyText: 'value'},
+ {name: 'Number value with copy', content: 2, copyText: 'two'},
+ {name: 'Node value with copy', content: value, copyText: 'value'},
+ {name: 'Empty value with copy', copyText: 'nothing to copy'},
+ {name: 'String value with custom title', content: 'value', contentTitle: "value's title"},
+ {name: 'Number value with custom title', content: 2, contentTitle: "value's title"},
+ {
+ name: 'Node value with custom title',
+ content: value,
+ contentTitle: "value's title",
+ },
+ {name: 'Empty value with custom title', contentTitle: "value's title"},
+ {
+ name: 'String long value',
+ content:
+ 'The HTML
element represents a description list. The element encloses a list of groups of terms (specified using the
element) and descriptions (provided by
elements). Common uses for this element are to implement a glossary or to display metadata (a list of key-value pairs)',
+ },
+ {
+ name: 'String long value with copy',
+ content:
+ 'The HTML
element represents a description list. The element encloses a list of groups of terms (specified using the
element) and descriptions (provided by
elements). Common uses for this element are to implement a glossary or to display metadata (a list of key-value pairs)',
+ copyText:
+ 'The HTML
element represents a description list. The element encloses a list of groups of terms (specified using the
element) and descriptions (provided by
elements). Common uses for this element are to implement a glossary or to display metadata (a list of key-value pairs)',
+ },
+ {
+ name: 'Number long value',
+ // eslint-disable-next-line no-loss-of-precision
+ content: 12345678901234567890123456789012345678901234567890123456789012345678901234567890,
+ },
+ {
+ name: 'Node long value',
+ content: (
+
+ The{' '}
+
+ HTML <dl>{' '}
+
+ element represents a description list. The element encloses a list of groups of
+ terms (specified using the{' '}
+
+ <dt>
+ {' '}
+ element) and descriptions (provided by{' '}
+
+ <dd>
+ {' '}
+ elements). Common uses for this element are to implement a glossary or to display
+ metadata (a list of key-value pairs).
+
+ ),
+ },
+ {
+ name: 'String long value without whitespace',
+ content:
+ 'https://example.com/long-long/like/beyond/the/farthest/lands/long/path/to/handle?and=some&list=of&query=parameters&that=is&overcomplicated=maybe&with=some&token=inside¬=really&readable=but&sometimes=useful',
+ },
+ {
+ name: 'String long looooooooooooooong looooooooooooooong looooooooooooooong looooooooooooooong value without multiline and with copy icon',
+ multilineName: true,
+ note: 'This is multiline value',
+ content:
+ 'https://example.com/long-long/like/beyond/the/farthest/lands/long/path/to/handle?and=some&list=of&query=parameters&that=is&overcomplicated=maybe&with=some&token=inside¬=really&readable=but&sometimes=useful',
+ copyText:
+ 'https://example.com/long-long/like/beyond/the/farthest/lands/long/path/to/handle?and=some&list=of&query=parameters&that=is&overcomplicated=maybe&with=some&token=inside¬=really&readable=but&sometimes=useful',
+ },
+ {
+ name: 'String value with tooltip',
+ content: 'value',
+ note: 'This is simple string value',
+ },
+ {
+ name: 'String value with very very very looooooooooooooong key',
+ content: 'value',
+ },
+ {
+ name: 'String value with very very very looooooooooooooong key and tooltip',
+ content: 'value',
+ note: 'This is simple string value',
+ },
+ {
+ name: 'Avatar with tooltip',
+ content: (
+
+ ),
+ note: 'This is avatar',
+ },
+ {
+ name: 'Label',
+ content: ,
+ },
+];
+
+export default {
+ title: 'Components/DefinitionList',
+ component: DefinitionList,
+ args: {
+ items,
+ responsive: false,
+ contentMaxWidth: 480,
+ },
+} as Meta;
+
+const DefaultTemplate: StoryFn = (args) => ;
+export const Default = DefaultTemplate.bind({});
+
+const TemplateWithIconInside: StoryFn = (args) => {
+ return (
+ e.copyText)} copyPosition="inside" />
+ );
+};
+export const ListWithIconInside = TemplateWithIconInside.bind({});
diff --git a/src/components/DefinitionList/__tests__/DefinitionList.test.tsx b/src/components/DefinitionList/__tests__/DefinitionList.test.tsx
new file mode 100644
index 00000000..ea1d0f05
--- /dev/null
+++ b/src/components/DefinitionList/__tests__/DefinitionList.test.tsx
@@ -0,0 +1,72 @@
+import React from 'react';
+
+import {render, screen} from '../../../../test-utils/utils';
+import {DefinitionList, b} from '../DefinitionList';
+
+const qaAttribute = 'definition-list';
+
+const getComponent = (props = {}) =>
+ render(
+ node value},
+ ]}
+ {...props}
+ />,
+ ).container;
+
+describe('components: DefinitionList', () => {
+ it('should render', () => {
+ getComponent();
+ const component = screen.getByTestId(qaAttribute);
+ expect(component).toBeVisible();
+ });
+ it('should render passed className', () => {
+ getComponent({className: 'testClassName'});
+ const component = screen.getByTestId(qaAttribute);
+ expect(component).toHaveClass('testClassName');
+ });
+
+ it('should render passed content title', () => {
+ const items = [{name: 'test1', content: 'value1', contentTitle: 'contentTitle1'}];
+ getComponent({items});
+ const component = screen.getByText('value1');
+ expect(component).toHaveAttribute('title', 'contentTitle1');
+ });
+ it('should render passed name title', () => {
+ const items = [{name: 'test1', nameTitle: 'nameTitle1'}];
+ getComponent({items});
+ const component = screen.getByText('test1');
+ expect(component).toHaveAttribute('title', 'nameTitle1');
+ });
+ it('should not render clipboard button by default', () => {
+ getComponent();
+ const copyButton = screen.queryByRole('button');
+ expect(copyButton).toBeNull();
+ });
+ it('should render clipboard button', () => {
+ const items = [{name: 'test1', content: 'value1', copyText: 'value1'}];
+ getComponent({items});
+
+ const copyButton = screen.getByRole('button');
+
+ expect(copyButton).toHaveClass(b('copy-button'));
+ });
+ it('should render in responsive mode', () => {
+ const items = [{name: 'test1', content: 'value1', copyText: 'value1'}];
+ getComponent({items, responsive: true});
+
+ const component = screen.getByTestId(qaAttribute);
+ expect(component).toHaveClass(b({responsive: true}));
+ });
+ it('should render with multiline term', () => {
+ const items = [{name: 'test1', content: 'value1', copyText: 'value1', multilineName: true}];
+ getComponent({items});
+
+ const component = screen.getByRole('term');
+ expect(component).toHaveClass(b('term-container', {multiline: true}));
+ });
+});
diff --git a/src/components/DefinitionList/index.ts b/src/components/DefinitionList/index.ts
new file mode 100644
index 00000000..881123f2
--- /dev/null
+++ b/src/components/DefinitionList/index.ts
@@ -0,0 +1,2 @@
+export {DefinitionList} from './DefinitionList';
+export type {DefinitionListProps, DefinitionListItem} from './DefinitionList';
diff --git a/src/components/DefinitionList/utils.ts b/src/components/DefinitionList/utils.ts
new file mode 100644
index 00000000..b7d4b485
--- /dev/null
+++ b/src/components/DefinitionList/utils.ts
@@ -0,0 +1,7 @@
+export function isUnbreakableOver(limit: number) {
+ return function (value: string): boolean {
+ const posibleLines = value.split(/\s+/);
+
+ return posibleLines.some((line) => line.length > limit);
+ };
+}
diff --git a/src/components/index.ts b/src/components/index.ts
index bedffe9c..f80f556c 100644
--- a/src/components/index.ts
+++ b/src/components/index.ts
@@ -1,6 +1,7 @@
export * from './AdaptiveTabs';
export * from './CookieConsent';
export * from './ChangelogDialog';
+export * from './DefinitionList';
export * from './DelayedTextInput';
export * from './FilePreview';
export * from './FormRow';