• HTML

    rating-feedback.html html

    <rating-feedback>
    	<form>
    		<rating-stars>
    			<fieldset>
    				<legend class="visually-hidden">Rate</legend>
    				<label>
    					<input type="radio" class="visually-hidden" name="rating" value="1">
    					<span class="label">☆</span>
    				</label>
    				<label>
    					<input type="radio" class="visually-hidden" name="rating" value="2">
    					<span class="label">☆</span>
    				</label>
    				<label>
    					<input type="radio" class="visually-hidden" name="rating" value="3">
    					<span class="label">☆</span>
    				</label>
    				<label>
    					<input type="radio" class="visually-hidden" name="rating" value="4">
    					<span class="label">☆</span>
    				</label>
    				<label>
    					<input type="radio" class="visually-hidden" name="rating" value="5">
    					<span class="label">☆</span>
    				</label>
    			</fieldset>
    		</rating-stars>
    		<div class="feedback" hidden>
    			<header>
    				<button button="button" class="hide" aria-label="Hide">×</button>
    				<p hidden>We're sorry to hear that! Your feedback is important, and we'd love to improve. Let us know how we can do better.</p>
    				<p hidden>Thank you for your honesty. We appreciate your feedback and will work on making things better.</p>
    				<p hidden>Thanks for your rating! If there's anything we can improve, we'd love to hear your thoughts.</p>
    				<p hidden>We're glad you had a good experience! If there's anything that could make it even better, let us know.</p>
    				<p hidden>Thank you for your support! We're thrilled you had a great experience. Your feedback keeps us motivated!</p>
    			</header>
    			<fieldset>
    				<label for="rating-feedback">Describe your experience (optional)</label>
    				<textarea id="rating-feedback"></textarea>
    				<input-button disabled>
    					<button type="submit" class="primary" disabled>Submit</button>
    				</input-button>
    			</fieldset>
    		</div>
    	</form>
    </rating-feedback>
    CSS

    rating-feedback.css css

    rating-feedback {
    	position: relative;
    	display: inline-flex;
    	flex-direction: column;
    	gap: var(--space-m);
    	width: 80%;
    	text-align: left;
    
    	header {
    		display: flex;
    		flex-direction: row-reverse;
    		gap: var(--space-s);
    		margin-block: var(--space-l);
    	}
    
    	.hide {
    		position: relative;
    		display: block;
    		box-sizing: border-box;
    		top: 0;
    		right: 0;
    		border: 0;
    		border-radius: var(--space-xs);
    		color: var(--color-text);
    		background: transparent;
    		height: var(--input-height);
    		font-size: var(--font-size-l);
    
    		&:hover,
    		&:focus {
    			background: rgba(0, 0, 0, 0.05);
    		}
    
    		&:active {
    			background: rgba(0, 0, 0, 0.1);
    		}
    	}
    
    	p {
    		margin: 0;
    	}
    
    	form {
    		display: flex;
    		flex-direction: column;
    	}
    
    	fieldset {
    		border: 0;
    		padding: 0;
    		margin: 0;
    	}
    
    	.feedback label {
    		display: block;
    		margin-bottom: var(--space-xxs);
    	}
    
    	textarea {
    		resize: vertical;
            width: 100%;
    		display: inline-block;
    		box-sizing: border-box;
    		background: var(--color-input);
    		color: var(--color-text);
    		border: 1px solid var(--color-border);
    		padding: var(--space-xs) var(--space-xxs);
    		font-size: var(--font-size-m);
            line-height: var(--line-height-m);
    		margin-bottom: var(--space-xs);
    	}
    }
    TS

    rating-feedback.ts ts

    import { setProperty, UIElement } from "../../../";
    import { type InputButton } from "../input-button/input-button";
    import { type RatingStars } from "../rating-stars/rating-stars";
    
    export class RatingFeedback extends UIElement<{
    	rating: number,
    	empty: boolean,
    	submitted: boolean
    }> {
    	static localName = 'rating-feedback'
    
    	init = {
    		rating: 0,
    		empty: true,
            submitted: false,
        }
    
    	connectedCallback() {
    		super.connectedCallback()
    
    		// Event listeners for rating changes and form submission
    		this.self
    			.on('change-rating', (e: Event) => {
    				this.set('rating', (e as CustomEvent<number>).detail)
    			})
    			.on('submit', (e: Event) => {
    				e.preventDefault()
    				this.set('submitted', true)
    				console.log('Feedback submitted')
    			})
    
    		// Event listener for hide button
    		this.first('.hide').on('click', () => {
    			const feedback = this.querySelector<HTMLElement>('.feedback')
    			if (feedback) feedback.hidden = true
    		})
    
    		// Event listener for texteare
    		this.first('textarea').on('input', (e: Event) => {
    			this.set('empty', (e.target as HTMLTextAreaElement)?.value.trim() === '')
    		})
    
    		// Effects on rating changes
    		const stars = this.querySelector<RatingStars>('rating-stars')
    		this.first('.feedback')
    			.sync(setProperty('hidden', () => this.get('submitted') || !(stars?.get('value') ?? 0)))
    		this.all('.feedback p')
    			.sync(setProperty('hidden', (_, index) => stars?.get('value') !== index + 1))
    
    		// Effect on empty state
    		this.first<InputButton>('input-button').pass({
    			disabled: 'empty'
    		})
    	}
    }
    RatingFeedback.define()