diff --git a/src/components/node/NodeImageSlideBlock/index.tsx b/src/components/node/NodeImageSlideBlock/index.tsx
new file mode 100644
index 00000000..c2efff13
--- /dev/null
+++ b/src/components/node/NodeImageSlideBlock/index.tsx
@@ -0,0 +1,150 @@
+import React, {
+  FC,
+  useMemo,
+  useState,
+  useEffect,
+  RefObject,
+  LegacyRef,
+  useRef,
+  useCallback,
+  MouseEventHandler,
+} from 'react';
+import { ImageSwitcher } from '../ImageSwitcher';
+import * as styles from './styles.scss';
+import { INode } from '~/redux/types';
+import classNames from 'classnames';
+import { getImageSize } from '~/utils/dom';
+import { UPLOAD_TYPES } from '~/redux/uploads/constants';
+
+interface IProps {
+  is_loading: boolean;
+  node: INode;
+  layout: {};
+  updateLayout: () => void;
+}
+
+const NodeImageSlideBlock: FC<IProps> = ({ node, is_loading, updateLayout }) => {
+  const [is_animated, setIsAnimated] = useState(false);
+  const [current, setCurrent] = useState(0);
+  const [height, setHeight] = useState(320);
+  const [loaded, setLoaded] = useState<Record<number, boolean>>({});
+  const refs = useRef<Record<number, HTMLDivElement>>({});
+  const [heights, setHeights] = useState({});
+
+  const [initial_offset, setInitialOffset] = useState(0);
+  const [initial_x, setInitialX] = useState(0);
+  const [offset, setOffset] = useState(0);
+  const [is_dragging, setIsDragging] = useState(false);
+  const slide = useRef();
+
+  const images = useMemo(
+    () =>
+      (node && node.files && node.files.filter(({ type }) => type === UPLOAD_TYPES.IMAGE)) || [],
+    [node]
+  );
+
+  // console.log({ heights });
+
+  const updateSizes = useCallback(() => {
+    const values = Object.keys(refs.current).map(key => {
+      const ref = refs.current[key];
+      if (!ref || !ref.getBoundingClientRect) return 0;
+      return ref.getBoundingClientRect().height;
+    });
+  }, [refs]);
+
+  const setRef = useCallback(
+    index => el => {
+      refs.current[index] = el;
+    },
+    [refs, heights, setHeights]
+  );
+
+  const onImageLoad = useCallback(index => () => setLoaded({ ...loaded, [index]: true }), [
+    setLoaded,
+    loaded,
+  ]);
+
+  // update outside hooks
+  useEffect(() => updateLayout(), [loaded]);
+
+  useEffect(() => {
+    updateSizes();
+    //
+    // if (!refs || !refs.current[current] || !loaded[current]) return setHeight(320);
+    //
+    // const el = refs.current[current];
+    //
+    // const element_height = el.getBoundingClientRect && el.getBoundingClientRect().height;
+    //
+    // setHeight(element_height);
+  }, [refs, current, loaded]);
+
+  // useEffect(() => {
+  // const timer = setTimeout(() => setIsAnimated(true), 250);
+  //
+  // return () => clearTimeout(timer);
+  // }, []);
+
+  const stopDragging = useCallback(() => {
+    window.removeEventListener('mouseup', stopDragging);
+    setIsDragging(false);
+  }, [setIsDragging]);
+
+  const startDragging: MouseEventHandler<HTMLDivElement> = useCallback(
+    event => {
+      window.addEventListener('mouseup', stopDragging);
+      setIsDragging(true);
+      setInitialX(event.clientX);
+      setInitialOffset(offset);
+    },
+    [setIsDragging, stopDragging, setInitialX, offset, setInitialOffset]
+  );
+
+  const onDrag = useCallback(
+    event => {
+      if (!is_dragging) return;
+
+      setOffset(initial_offset + event.clientX - initial_x);
+    },
+    [is_dragging, initial_x, setOffset, initial_offset]
+  );
+
+  return (
+    <div className={classNames(styles.wrap, { is_loading, is_animated })}>
+      <div
+        className={styles.image_container}
+        style={{
+          height,
+          transform: `translate(${offset}px, 0)`,
+          width: `${images.length * 100}%`,
+        }}
+        onMouseDown={startDragging}
+        onMouseMove={onDrag}
+        ref={slide}
+      >
+        {(is_loading || !loaded[0] || !images.length) && <div className={styles.placeholder} />}
+
+        {images.map((file, index) => (
+          <div
+            className={classNames(styles.image_wrap, {
+              is_active: index === current && loaded[index],
+            })}
+            ref={setRef(index)}
+            key={file.id}
+          >
+            <img
+              className={styles.image}
+              src={getImageSize(file, 'node')}
+              alt=""
+              key={file.id}
+              onLoad={onImageLoad(index)}
+            />
+          </div>
+        ))}
+      </div>
+    </div>
+  );
+};
+
+export { NodeImageSlideBlock };
diff --git a/src/components/node/NodeImageSlideBlock/styles.scss b/src/components/node/NodeImageSlideBlock/styles.scss
new file mode 100644
index 00000000..c36ee620
--- /dev/null
+++ b/src/components/node/NodeImageSlideBlock/styles.scss
@@ -0,0 +1,56 @@
+.wrap {
+  overflow: hidden;
+  position: relative;
+  min-width: 0;
+  width: 100%;
+
+  &:global(.is_animated) {
+    .image_container {
+      transition: height 0.5s;
+    }
+
+    .image_wrap {
+      transition: opacity 0.5s;
+    }
+  }
+}
+
+.image_container {
+  background: $node_image_bg;
+  border-radius: $panel_radius 0 0 $panel_radius;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  position: relative;
+  overflow: hidden;
+  user-select: none;
+
+  .image {
+    max-height: 960px;
+    max-width: 100%;
+    opacity: 1;
+    border-radius: $radius $radius 0 0;
+  }
+}
+
+.image_wrap {
+  width: 100%;
+  // top: 0;
+  // left: 0;
+  // opacity: 0;
+  pointer-events: none;
+  touch-action: none;
+  z-index: 1;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+
+  &:global(.is_active) {
+    opacity: 1;
+  }
+}
+
+.placeholder {
+  background: red;
+  height: 320px;
+}
diff --git a/src/redux/node/constants.ts b/src/redux/node/constants.ts
index 5f34723a..64bd54c8 100644
--- a/src/redux/node/constants.ts
+++ b/src/redux/node/constants.ts
@@ -1,6 +1,6 @@
 import { FC } from 'react';
 import { IBlock, INode, ValueOf, IComment } from '../types';
-import { NodeImageBlock } from '~/components/node/NodeImageBlock';
+import { NodeImageSlideBlock } from '~/components/node/NodeImageSlideBlock';
 import { ImageEditor } from '~/components/editors/ImageEditor';
 import { TextEditor } from '~/components/editors/TextEditor';
 import { DIALOGS } from '../modal/constants';
@@ -63,7 +63,7 @@ type INodeComponents = Record<
 >;
 
 export const NODE_COMPONENTS: INodeComponents = {
-  [NODE_TYPES.IMAGE]: NodeImageBlock,
+  [NODE_TYPES.IMAGE]: NodeImageSlideBlock,
 };
 
 export const EMPTY_COMMENT: IComment = {