Star Rating Animation - Code
import cn from "classnames";

import styles from "./StarRating.module.scss";

interface RatingStarProps {
	id: string;
	delayIndex: number;
}

interface RatingRadioProps {
	id: string;
}

interface StarRatingAnimationProps {
	name?: string;
	legend?: string;
	className?: string;
}

const RatingStar = ({ id, delayIndex }: RatingStarProps) => (
	<label
		className={cn(styles.rating__label, styles[`rating__label-${id}`], styles[`rating__label--delay${delayIndex}`])}
		htmlFor={`rating-${id}`}
	>
		<span className="sr-only">{id} stars</span>
		<svg className={styles.rating__star} width="32" height="32" viewBox="0 0 32 32" aria-hidden="true">
			<g stroke="#C3CCD9" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
				<g transform="translate(16,16) rotate(180)">
					<polygon
						className={styles["rating__star-stroke"]}
						points="0,15 4.41,6.07 14.27,4.64 7.13,-2.32 8.82,-12.14 0,-7.5 -8.82,-12.14 -7.13,-2.32 -14.27,4.64 -4.41,6.07"
						fill="none"
					/>
					<polygon
						className={styles["rating__star-fill"]}
						points="0,15 4.41,6.07 14.27,4.64 7.13,-2.32 8.82,-12.14 0,-7.5 -8.82,-12.14 -7.13,-2.32 -14.27,4.64 -4.41,6.07"
						fill="none"
					/>
				</g>
				<g transform="translate(16,16)" strokeDasharray="12 12" strokeDashoffset="12">
					<polyline className={styles["rating__star-line"]} transform="rotate(0)" points="0 4,0 16" />
					<polyline className={styles["rating__star-line"]} transform="rotate(72)" points="0 4,0 16" />
					<polyline className={styles["rating__star-line"]} transform="rotate(144)" points="0 4,0 16" />
					<polyline className={styles["rating__star-line"]} transform="rotate(216)" points="0 4,0 16" />
					<polyline className={styles["rating__star-line"]} transform="rotate(288)" points="0 4,0 16" />
				</g>
			</g>
		</svg>
	</label>
);

const RatingRadio = ({ id }: RatingRadioProps) => (
	<input id={`rating-${id}`} className={cn(styles.rating__input, styles[`rating__input-${id}`])} type="radio" name="rating" value={id} />
);

export const StarRatingAnimation = ({ className }: StarRatingAnimationProps) => {
	const ratings = ["1", "2", "3", "4", "5"];

	return (
		<fieldset className={cn(styles.rating, className)}>
			<legend className="sr-only">Star rating</legend>
			{ratings.map((id) => (
				<RatingRadio key={`radio-${id}`} id={id} />
			))}
			{ratings.map((id, index) => (
				<RatingStar key={`star-${id}`} id={id} delayIndex={index} />
			))}
		</fieldset>
	);
};
Star Rating Animation - Preview
Star rating
3D Media Control Button - Code
import cn from "classnames";
import { useState } from "react";
import styles from "./MediaControlButton.module.scss";

interface MediaControlButtonProps {
	iconType: "pause" | "stop";
}

export const MediaControlButton = ({ iconType }: MediaControlButtonProps) => {
	const [isActive, setIsActive] = useState(true);
	const iconDivCount = iconType === "pause" ? 4 : 2;

	const handleClick = () => {
		setIsActive(!isActive);
	};

	return (
		<button
			type="button"
			onClick={handleClick}
			aria-pressed={isActive}
			aria-label={iconType === "pause" ? (isActive ? "Pause media" : "Play media") : isActive ? "Stop media" : "Start media"}
			className={cn(styles["media-control-button"], {
				[styles["media-control-button--active"]]: isActive,
				[styles["media-control-button--pause-style"]]: iconType === "pause",
				[styles["media-control-button--stop-style"]]: iconType === "stop",
			})}
		>
			<div
				className={cn(styles["icon-wrapper"], {
					[styles["icon-wrapper--active"]]: isActive,
				})}
			>
				{Array.from({ length: iconDivCount }).map((_, index) => (
					<div
						key={`${iconType}-${index + 1}`}
						className={cn(styles.icon, {
							[styles["icon--pause-style"]]: iconType === "pause",
							[styles["icon--stop-style"]]: iconType === "stop",
						})}
					/>
				))}
			</div>
		</button>
	);
};
3D Media Control Button - Preview
Text Field with Floating Label - Code
import cn from "classnames";
import { useState } from "react";
import styles from "./TextFieldWithFloatingLabel.module.scss";

export const TextFieldWithFloatingLabel = () => {
	const [value, setValue] = useState("");
	const [isValid, setIsValid] = useState(true);

	const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
		const newValue = e.target.value;
		setValue(newValue);

		const phonePattern = /^[0-9\s\-\(\)\+]*$/;
		setIsValid(phonePattern.test(newValue));
	};

	const hasValue = value.length > 0;

	return (
		<div
			className={cn(styles.textfield, {
				[styles["textfield--has-value"]]: hasValue,
				[styles["textfield--is-invalid"]]: !isValid,
			})}
		>
			<label
				className={cn(styles.textfield__label, {
					[styles["textfield__label--has-value"]]: hasValue,
					[styles["textfield__label--is-invalid"]]: !isValid,
				})}
				htmlFor="phone-input"
			>
				Phone
			</label>
			<div className={styles.textfield__inputWrapper}>
				<input
					id="phone-input"
					type="tel"
					className={cn(styles.textfield__input, {
						[styles["textfield__input--has-value"]]: hasValue,
						[styles["textfield__input--is-invalid"]]: !isValid,
					})}
					value={value}
					onChange={handleChange}
					aria-invalid={!isValid}
					placeholder=""
				/>
			</div>
			<p className={cn(styles["help-text"], !isValid && styles["help-text--error"])}>
				{isValid && "Please enter your phone number"}
				{!isValid && (
					<>
						<i className="fa-solid fa-circle-exclamation" /> Letters are not allowed in phone numbers
					</>
				)}
			</p>
		</div>
	);
};
Text Field with Floating Label - Preview

Please enter your phone number

More Examples Coming Soon

Stay tuned for more interactive components, animations, and code snippets.

Tina Holdcroft

Interested in working together or just want to say hello? Feel free to get in touch!

about

About MeMy ExperienceMy Tools

gallery

Code SnippetsPhotosPrototypesIllustrations & Icons
githublinkedincodependribbble