diff --git a/projects/demo/src/modules/app/app.routes.ts b/projects/demo/src/modules/app/app.routes.ts
index 2965f3be0e38..38a5129878d0 100644
--- a/projects/demo/src/modules/app/app.routes.ts
+++ b/projects/demo/src/modules/app/app.routes.ts
@@ -621,6 +621,11 @@ export const ROUTES: Routes = [
title: 'Rating',
loadComponent: async () => import('../components/rating'),
}),
+ route({
+ path: DemoRoute.Pulse,
+ title: 'Pulse',
+ loadComponent: async () => import('../components/pulse'),
+ }),
route({
path: DemoRoute.Range,
loadChildren: async () =>
diff --git a/projects/demo/src/modules/app/demo-routes.ts b/projects/demo/src/modules/app/demo-routes.ts
index c2dca2c22bed..f47f786a09a7 100644
--- a/projects/demo/src/modules/app/demo-routes.ts
+++ b/projects/demo/src/modules/app/demo-routes.ts
@@ -105,6 +105,7 @@ export const DemoRoute = {
Pagination: '/navigation/pagination',
Radio: '/components/radio',
Rating: '/components/rating',
+ Pulse: '/components/pulse',
Range: '/components/range',
CalendarRange: '/components/calendar-range',
Select: '/components/select',
diff --git a/projects/demo/src/modules/app/pages.ts b/projects/demo/src/modules/app/pages.ts
index 6d509ced8284..ade80f415663 100644
--- a/projects/demo/src/modules/app/pages.ts
+++ b/projects/demo/src/modules/app/pages.ts
@@ -713,6 +713,12 @@ export const pages: TuiDocPages = [
keywords: 'рейтинг, оценка, звезда, rating, star, rate',
route: DemoRoute.Rating,
},
+ {
+ section: 'Components',
+ title: 'Pulse',
+ keywords: 'сигнал, пульс, pulse, signal',
+ route: DemoRoute.Pulse,
+ },
{
section: 'Components',
title: 'Selects',
diff --git a/projects/demo/src/modules/components/pulse/examples/1/index.html b/projects/demo/src/modules/components/pulse/examples/1/index.html
new file mode 100644
index 000000000000..8f723199212f
--- /dev/null
+++ b/projects/demo/src/modules/components/pulse/examples/1/index.html
@@ -0,0 +1,7 @@
+
diff --git a/projects/demo/src/modules/components/pulse/examples/1/index.ts b/projects/demo/src/modules/components/pulse/examples/1/index.ts
new file mode 100644
index 000000000000..5eef106d80a5
--- /dev/null
+++ b/projects/demo/src/modules/components/pulse/examples/1/index.ts
@@ -0,0 +1,14 @@
+import {Component} from '@angular/core';
+import {changeDetection} from '@demo/emulate/change-detection';
+import {encapsulation} from '@demo/emulate/encapsulation';
+import {TuiButtonDirective} from '@taiga-ui/core';
+import {TuiPulseComponent} from '@taiga-ui/kit';
+
+@Component({
+ standalone: true,
+ imports: [TuiPulseComponent, TuiButtonDirective],
+ templateUrl: './index.html',
+ encapsulation,
+ changeDetection,
+})
+export default class ExampleComponent {}
diff --git a/projects/demo/src/modules/components/pulse/examples/import/import.md b/projects/demo/src/modules/components/pulse/examples/import/import.md
new file mode 100644
index 000000000000..6891482115f3
--- /dev/null
+++ b/projects/demo/src/modules/components/pulse/examples/import/import.md
@@ -0,0 +1,13 @@
+```ts
+import {TuiPulseComponent} from '@taiga-ui/kit';
+// ...
+
+@Component({
+ standalone: true,
+ imports: [
+ // ...
+ TuiPulseComponent,
+ ],
+})
+export class MyComponent {}
+```
diff --git a/projects/demo/src/modules/components/pulse/examples/import/template.md b/projects/demo/src/modules/components/pulse/examples/import/template.md
new file mode 100644
index 000000000000..706b79132f54
--- /dev/null
+++ b/projects/demo/src/modules/components/pulse/examples/import/template.md
@@ -0,0 +1,3 @@
+```html
+
+```
diff --git a/projects/demo/src/modules/components/pulse/index.html b/projects/demo/src/modules/components/pulse/index.html
new file mode 100644
index 000000000000..1999b2484986
--- /dev/null
+++ b/projects/demo/src/modules/components/pulse/index.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
diff --git a/projects/demo/src/modules/components/pulse/index.ts b/projects/demo/src/modules/components/pulse/index.ts
new file mode 100644
index 000000000000..926e795dfdb3
--- /dev/null
+++ b/projects/demo/src/modules/components/pulse/index.ts
@@ -0,0 +1,11 @@
+import {Component} from '@angular/core';
+import {changeDetection} from '@demo/emulate/change-detection';
+import {TuiDemo} from '@demo/utils';
+
+@Component({
+ standalone: true,
+ imports: [TuiDemo],
+ templateUrl: './index.html',
+ changeDetection,
+})
+export default class PageComponent {}
diff --git a/projects/kit/components/index.ts b/projects/kit/components/index.ts
index 132c02f12768..a770b2474ec3 100644
--- a/projects/kit/components/index.ts
+++ b/projects/kit/components/index.ts
@@ -26,6 +26,7 @@ export * from '@taiga-ui/kit/components/pdf-viewer';
export * from '@taiga-ui/kit/components/pin';
export * from '@taiga-ui/kit/components/preview';
export * from '@taiga-ui/kit/components/progress';
+export * from '@taiga-ui/kit/components/pulse';
export * from '@taiga-ui/kit/components/push';
export * from '@taiga-ui/kit/components/radio';
export * from '@taiga-ui/kit/components/radio-list';
diff --git a/projects/kit/components/pulse/index.ts b/projects/kit/components/pulse/index.ts
new file mode 100644
index 000000000000..4697b515716a
--- /dev/null
+++ b/projects/kit/components/pulse/index.ts
@@ -0,0 +1 @@
+export * from './pulse.component';
diff --git a/projects/kit/components/pulse/ng-package.json b/projects/kit/components/pulse/ng-package.json
new file mode 100644
index 000000000000..bebf62dcb5e5
--- /dev/null
+++ b/projects/kit/components/pulse/ng-package.json
@@ -0,0 +1,5 @@
+{
+ "lib": {
+ "entryFile": "index.ts"
+ }
+}
diff --git a/projects/kit/components/pulse/pulse.component.ts b/projects/kit/components/pulse/pulse.component.ts
new file mode 100644
index 000000000000..c5d9256fd572
--- /dev/null
+++ b/projects/kit/components/pulse/pulse.component.ts
@@ -0,0 +1,27 @@
+import {ChangeDetectionStrategy, Component, inject, Input} from '@angular/core';
+import {
+ TUI_ANIMATIONS_SPEED,
+ tuiFadeIn,
+ tuiScaleIn,
+ tuiToAnimationOptions,
+} from '@taiga-ui/core';
+
+@Component({
+ standalone: true,
+ selector: 'tui-pulse',
+ template: '',
+ styleUrls: ['./pulse.style.less'],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ animations: [tuiFadeIn, tuiScaleIn],
+ host: {
+ '[@tuiFadeIn]': 'animation',
+ '[@tuiScaleIn]': 'animation',
+ '[style.--t-animation-state]': "playing ? 'running' : 'paused'",
+ },
+})
+export class TuiPulseComponent {
+ @Input()
+ public playing = true;
+
+ protected readonly animation = tuiToAnimationOptions(inject(TUI_ANIMATIONS_SPEED));
+}
diff --git a/projects/kit/components/pulse/pulse.style.less b/projects/kit/components/pulse/pulse.style.less
new file mode 100644
index 000000000000..19f65568ef32
--- /dev/null
+++ b/projects/kit/components/pulse/pulse.style.less
@@ -0,0 +1,75 @@
+@keyframes tuiPulse {
+ 0% {
+ opacity: 0.3;
+ transform: scale(1);
+ }
+
+ 20% {
+ opacity: 0;
+ transform: scale(0.5);
+ }
+
+ 25% {
+ opacity: 0.3;
+ transform: scale(1);
+ }
+
+ 45% {
+ opacity: 0;
+ transform: scale(0.5);
+ }
+
+ 50% {
+ opacity: 0.3;
+ transform: scale(1);
+ }
+
+ 70% {
+ opacity: 0;
+ transform: scale(0.5);
+ }
+
+ 75% {
+ opacity: 0.3;
+ transform: scale(1);
+ }
+
+ 95% {
+ opacity: 0;
+ transform: scale(0.5);
+ }
+
+ 100% {
+ opacity: 0.3;
+ transform: scale(1);
+ }
+}
+
+:host {
+ position: relative;
+ color: var(--tui-primary);
+
+ &:before {
+ content: '';
+ position: absolute;
+ top: -0.5rem;
+ left: -0.5rem;
+ width: 1rem;
+ height: 1rem;
+ border-radius: 100%;
+ background: currentColor;
+ opacity: 0.3;
+ animation: tuiPulse 3s ease-in-out infinite;
+ animation-play-state: var(--t-animation-state);
+ }
+
+ &:after {
+ content: '';
+ position: absolute;
+ width: 0.5rem;
+ height: 0.5rem;
+ border-radius: 100%;
+ transform: translate(-50%, -50%);
+ background: currentColor;
+ }
+}