<div class="container"></div>
.tag:first-of-type {
      border-radius: 50px 0px 0px 50px;
}
 .tag:last-of-type {
       border-radius: 0px 50px 50px 0px;
}

.tag:last-of-type>.slider-button {
		 display:none !important;
}

span{
	font-family:sans-serif !important;
}
//ES6 const, let
//ES6 Destructuring
const { Component, useRef, Fragment, useState } = React;

// import React,{ useState, useRef,Fragment } from 'react'
const _tags = [
	{
		name: "Action",
		color: "red"
	},
	{
		name: "Romance",
		color: "purple"
	},
	{
		name: "Comedy",
		color: "orange"
	},
	{
		name: "Horror",
		color: "black"
	}
];

const getPercentage = (containerWidth: number, distanceMoved: number) => {
	return (distanceMoved / containerWidth) * 100;
};

const limitNumberWithinRange = (
	value: number,
	min: number,
	max: number
): number => {
	return Math.min(Math.max(value, min), max);
};

const nearestN = (N: number, number: number) => Math.ceil(number / N) * N;
interface TagSectionProps {
	name: string;
	color: string;
	width: number;
	onSliderSelect: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
}

const TagSection = ({
	name,
	color,
	width,
	onSliderSelect
}: TagSectionProps) => {
	return (
		<div
			className="tag"
			style={{
				...styles.tag,
				background: color,
				width: width + "%"
			}}
		>
			<span style={styles.tagText}>{name}</span>
			<span style={{ ...styles.tagText, fontSize: 12 }}>{width + "%"}</span>

			<div
				style={styles.sliderButton}
				onPointerDown={onSliderSelect}
				className="slider-button"
			>
				<img src={"https://assets.codepen.io/576444/slider-arrows.svg"} height={"30%"} />
			</div>
		</div>
	);
};

const TagSlider = () => {
	const [widths, setWidths] = useState<number[]>(
		new Array(_tags.length).fill(100 / _tags.length)
	);
	const [tags, setTags] = useState(_tags);
	const TagSliderRef = useRef<HTMLDivElement>(null);

	return (
		<div>
		
		<div
			ref={TagSliderRef}
			style={{
				width: "100%",
				display: "flex",
				   backgroundColor:'transparent'
			}}
		>
			{tags.map((tag, index) => (
				<TagSection
					width={widths[index]}
					key={index}
					noSliderButton={index === tags.length - 1}
					name={tag.name}
					onSliderSelect={(e) => {
						e.preventDefault();
						document.body.style.cursor = "ew-resize";

						const startDragX = e.pageX;
						const sliderWidth = TagSliderRef.current.offsetWidth;

						const resize = (e: MouseEvent & TouchEvent) => {
							e.preventDefault();
							const endDragX = e.touches ? e.touches[0].pageX : e.pageX;
							const distanceMoved = endDragX - startDragX;
							const maxPercent = widths[index] + widths[index + 1];

							const percentageMoved = nearestN(1, getPercentage(sliderWidth, distanceMoved))
							// const percentageMoved = getPercentage(sliderWidth, distanceMoved);

							const _widths = widths.slice();

							const prevPercentage = _widths[index];
							
							const newPercentage = prevPercentage + percentageMoved;
							const currentSectionWidth = limitNumberWithinRange(
								newPercentage,
								0,
								maxPercent
							);
							_widths[index] = currentSectionWidth;

							const nextSectionIndex = index + 1;

							const nextSectionNewPercentage =
								_widths[nextSectionIndex] - percentageMoved;
							const nextSectionWidth = limitNumberWithinRange(
								nextSectionNewPercentage,
								0,
								maxPercent
							);
							_widths[nextSectionIndex] = nextSectionWidth;

							if (tags.length > 2) {
								if (_widths[index] === 0) {
									_widths[nextSectionIndex] = maxPercent;
									_widths.splice(index, 1);
									setTags(tags.filter((t, i) => i !== index));
									removeEventListener();
								}
								if (_widths[nextSectionIndex] === 0) {
									_widths[index] = maxPercent;
									_widths.splice(nextSectionIndex, 1);
									setTags(tags.filter((t, i) => i !== nextSectionIndex));
									removeEventListener();
								}
							}

							setWidths(_widths);
						};

						window.addEventListener("pointermove", resize);
						window.addEventListener("touchmove", resize);

						const removeEventListener = () => {
							window.removeEventListener("pointermove", resize);
							window.removeEventListener("touchmove", resize);
						};

						const handleEventUp = (e: Event) => {
							e.preventDefault();
							document.body.style.cursor = "initial";
							removeEventListener();
						};

						window.addEventListener("touchend", handleEventUp);
						window.addEventListener("pointerup", handleEventUp);
					}}
					color={tag.color}
				/>
			))}
		</div>
<button onClick={()=>{
	setTags(_tags)
	setWidths(new Array(_tags.length).fill(100 / _tags.length))
}} style={{marginTop:10}}>Refresh</button>
</div>
	);
};

type StylesType = { [key: string]: React.CSSProperties };

const styles: StylesType = {
	tag: {
		padding: 20,
		textAlign: "center",
		position: "relative",
		borderRightWidth: ".1em",
		borderRightStyle: "solid",
		borderRightColor: "white",
		boxSizing: "border-box",
		borderLeftWidth: ".1em",
		borderLeftStyle: "solid",
		borderLeftColor: "white"
	},
	tagText: {
		color: "white",
		fontWeight: 700,
		userSelect: "none",
		display: "block",
		overflow: "hidden",
		fontFamily: "serif"
	},
	sliderButton: {
		width: "2em",
		height: "2em",
		backgroundColor: "white",
		position: "absolute",
		borderRadius: "2em",
		right: "calc(-1.1em)",
		top: 0,
		display: "flex",
		justifyContent: "center",
		alignItems: "center",
		bottom: 0,
		margin: "auto",
		zIndex: 10,
		cursor: "ew-resize",
		userSelect: "none"
	}
};

ReactDOM.render(<TagSlider />, document.querySelector(".container"));
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js
  3. https://unpkg.com/@types/react@16.8.6/index.d.ts
  4. https://unpkg.com/@types/react-dom@16.8.6/index.d.ts
  5. https://unpkg.com/@types/react-dom@16.8.4/index.d.ts