Video Call Hand-Raise Queue — Free Moderator Queue Panel HTML CSS JS

Video Call Hand-Raise Queue · Dashboards · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Raise-order queue
Array push order is the display order — first raised, first shown.
Efficient live timestamps
A separate interval updates just the time labels, not the full list.
Per-row moderator actions
"Let them speak" and "Lower hand" both remove the row, with distinct real-world intent.
Animated entry
New hand-raises animate in with a short rise-and-fade.
Next-up highlight
The first row's order badge is visually distinguished from the rest.
Initials avatars
Colored circles generated from names, no image assets required.
Empty state
A clear message replaces the list when no one is waiting.
Live waiting count
A badge in the header always reflects the current queue length.

About this UI Snippet

Video Call Hand-Raise Queue — An Ordered Moderator Panel

Screenshot of the Video Call Hand-Raise Queue snippet rendered live

Once a video call passes a handful of participants, "unmute yourself when you want to talk" breaks down — people talk over each other, or the loudest voice wins by default. A hand-raise queue fixes that by giving the moderator an ordered, first-raised-first-served list with clear per-person actions. This snippet builds that panel in plain HTML, CSS, and vanilla JavaScript.

Ordered by raise time, not name or role

The queue is a plain array of { id, name, raisedAt } objects, and its array order *is* the display order — the person who raised their hand first sits at position one and gets a highlighted gold badge, distinguishing them as next up. There's no separate sort step because entries are pushed onto the array in the order hands go up, which is exactly the ordering a moderator needs.

Live "time since raised" without re-rendering everything

Each row's timestamp is stored as raw raisedAt data on the element (data-raised) and a lightweight setInterval updates just the text content of every .hrq-time element once a second — deliberately *not* calling the full render() function, which would rebuild every row's HTML including the buttons, just to update a clock. This separation keeps the always-running ticker cheap regardless of queue size.

Two actions, one outcome, different intent

Both "Let them speak" and "Lower hand" remove the person from the queue — the difference is what a real integration does *before* removing them: "Let them speak" would unmute and spotlight the participant, while "Lower hand" simply dismisses the request. Keeping both wired to the same filter()-based removal in the demo keeps the queue logic simple while leaving the natural extension point clearly commented.

New entries animate in

Each <li> carries a short hrqIn keyframe animation (a slight rise-and-fade) so a newly raised hand doesn't just pop into the list — useful feedback for a moderator glancing at the panel between other tasks, signaling "something changed here" without a loud notification.

Overflow-safe names, initials avatars

As with other roster-style widgets in this library, names truncate cleanly with an ellipsis and each row gets a colored initials avatar — no image dependency, so it works immediately with any real participant list.

Customizing it

Wire "Let them speak" to your video SDK's unmute/spotlight call, "Lower hand" to a dismissal-only event, and replace the simulate button with your platform's real hand-raise event. Pair it with video call grid for the main call layout.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Rather than tracing the queue-ordering and timer logic by hand, paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly why array push order is used as the display order instead of sorting by raisedAt on every render, and how the separate setInterval for timestamps avoids rebuilding the whole list just to update a clock. The same assistant can help optimize it — for example asking whether the timestamp interval should pause when the browser tab is backgrounded, or how to handle two hands raised in the same millisecond. It's also useful for extending the panel: ask it to add a "raise your own hand" button for the current user's own row, a maximum queue size with an overflow message, or sound/visual notification when a new hand is raised while the moderator is looking elsewhere. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a "video call hand-raise queue" moderator panel in plain HTML, CSS, and JavaScript with no library.

Requirements:
- An array of participant objects each with an id, a name, and a raisedAt timestamp, where the array's own order is treated as the queue's display order (new raises are pushed to the end) rather than being separately sorted on every render.
- Each queue row rendered with an order-position badge (the first row visually distinguished as "next up"), a colored initials avatar generated from the name (no image assets), the name, a "time since raised" label, and two action buttons: "Let them speak" and "Lower hand".
- Both action buttons must remove that participant from the queue array and re-render the list, but the code should clearly distinguish their real-world intent (for example via a comment) since a production integration would unmute/spotlight the participant for one action but not the other.
- A separate, lightweight timer (not tied to the main render function) that updates every row's "time since raised" text once per second by reading a raw timestamp stored in a data attribute, without re-rendering the entire list's markup on every tick.
- New entries added to the queue must visually animate in (for example a brief rise-and-fade) rather than appearing instantly.
- An empty-state message shown only when the queue has zero entries, and a live count badge showing how many people are currently waiting.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA queue of three raised hands renders, ordered by raise time.
  2. 2
    Click "+ Simulate a hand raise"A new participant is added to the end of the queue with a rise-in animation.
  3. 3
    Watch the timestampsEach row's "time ago" label updates every second without re-rendering the list.
  4. 4
    Click "Let them speak" or "Lower hand"The person is removed from the queue and the remaining order updates.
  5. 5
    Empty the queueAn empty-state message appears once no one is waiting.
  6. 6
    Connect real eventsReplace the simulate button and demo actions with your video SDK's hand-raise API.

Real-world uses

Common Use Cases

Video conferencing platforms
The core moderator panel alongside video call grid.
Webinars and town halls
Manage Q&A order fairly for large audiences.
Virtual classrooms
Let a teacher call on students in the order hands went up.
Live-streamed panels and AMAs
Queue audience questions for a host to work through.
Community and town-hall meetings
Fair speaking order for public comment sessions.
Learning ordered-queue patterns
A reference for array-order-as-display-order — compare with activity feed.

Got questions?

Frequently Asked Questions

The queue array\'s own order is the display order — a new hand raise is pushed onto the end of the array, so the person who raised first naturally sits at index 0. The first row also gets a distinct gold order badge to make "who\'s next" visually unambiguous at a glance, without any separate sorting logic.

A dedicated setInterval running once a second selects every .hrq-time element directly and updates only its text content from the raw raisedAt value stored in a data attribute, deliberately avoiding a call to the full render() function that would rebuild every row\'s markup (including buttons and avatars) just to refresh a clock. This keeps the always-running ticker cheap no matter how long the queue gets.

In this demo both simply remove the person from the queue via the same filter() call, since the demo has no real audio/video backend — but they represent different real actions: "Let them speak" is where you\'d call your video SDK\'s unmute-and-spotlight API before removing the entry, while "Lower hand" is a moderator dismissing the request with no spotlight change. The comment in the click handler marks exactly where that distinction belongs.

Replace the simulate button\'s click handler with your SDK\'s hand-raise event listener (pushing a new { id, name, raisedAt } entry when it fires), and inside the "Let them speak" branch of the actions handler, call your SDK\'s unmute/spotlight method before filtering the person out of the queue array.

Hold the queue array in component state; pushing a new raise and filtering on an action both become standard state updates (setQueue in React, a mutated ref in Vue, or a component field in Angular). For the live timestamps, keep a separate "now" tick in state updated once a second and compute each row\'s time-ago string from it during render — the framework\'s own diffing avoids the manual DOM-only update this vanilla version does by hand.