Gradio-Community/custom-html-gallery huggingface dataset:
Gradio custom HTML component: Star Rating
Author: gradio
Category: input
Tags: input, rating, stars
Description: Click stars to set a rating from 1 to 5

Head:

HTML template:
<h2>${label} rating:</h2>
${Array.from({length: 5}, (_, i) => `<img class='${i < value ? '' : 'faded'}' src='https://upload.wikimedia.org/wikipedia/commons/d/df/Award-star-gold-3d.svg'>`).join('')}

CSS:
img { height: 50px; display: inline-block; cursor: pointer; }
.faded { filter: grayscale(100%); opacity: 0.3; }

JavaScript (on load):
const imgs = element.querySelectorAll('img');
imgs.forEach((img, index) => {
    img.addEventListener('click', () => {
        props.value = index + 1;
    });
});

Python code:
class StarRating(gr.HTML):
    def __init__(self, label, value=0, **kwargs):
        html_template = """
        <h2>${label} rating:</h2>
        ${Array.from({length: 5}, (_, i) => `<img class='${i < value ? '' : 'faded'}' src='https://upload.wikimedia.org/wikipedia/commons/d/df/Award-star-gold-3d.svg'>`).join('')}
        """
        css_template = """
            img { height: 50px; display: inline-block; cursor: pointer; }
            .faded { filter: grayscale(100%); opacity: 0.3; }
        """
        js_on_load = """
            const imgs = element.querySelectorAll('img');
            imgs.forEach((img, index) => {
                img.addEventListener('click', () => {
                    props.value = index + 1;
                });
            });
        """
        super().__init__(
            value=value, label=label,
            html_template=html_template,
            css_template=css_template,
            js_on_load=js_on_load, **kwargs
        )

    def api_info(self):
        return {"type": "integer", "minimum": 0, "maximum": 5}
Gradio custom HTML component: Button Set
Author: gradio
Category: input
Tags: input, buttons, events
Description: Multiple buttons that trigger events with click data

Head:

HTML template:
<button id='A'>A</button>
<button id='B'>B</button>
<button id='C'>C</button>

CSS:
button {
    padding: 10px 20px;
    background-color: #f97316;
    color: white;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    font-weight: 600;
    margin-right: 8px;
    transition: background 0.15s;
}
button:hover { background-color: #ea580c; }

JavaScript (on load):
const buttons = element.querySelectorAll('button');
buttons.forEach(button => {
    button.addEventListener('click', () => {
        trigger('click', {clicked: button.innerText});
    });
});

Python code:
button_set = gr.HTML(
    html_template="""
    <button id='A'>A</button>
    <button id='B'>B</button>
    <button id='C'>C</button>
    """,
    css_template="""
    button {
        padding: 10px 20px;
        background-color: #f97316;
        color: white; border: none;
        border-radius: 8px; cursor: pointer;
    }
    button:hover { background-color: #ea580c; }
    """,
    js_on_load="""
    const buttons = element.querySelectorAll('button');
    buttons.forEach(button => {
        button.addEventListener('click', () => {
            trigger('click', {clicked: button.innerText});
        });
    });
    """
)

def on_button_click(evt: gr.EventData):
    return evt.clicked

button_set.click(on_button_click, outputs=clicked_box)
Gradio custom HTML component: Progress Bar
Author: gradio
Category: display
Tags: display, progress, animation
Description: Interactive progress bar - click the track to set progress

Head:

HTML template:
<div class="progress-container">
    <div class="progress-label">${label}</div>
    <div class="progress-track">
        <div class="progress-fill" style="width: ${value}%"></div>
    </div>
    <div class="progress-text">${value}%</div>
</div>

CSS:
.progress-container { padding: 8px 0; }
.progress-label { font-weight: 600; margin-bottom: 8px; font-size: 15px; }
.progress-track { width: 100%; height: 24px; background: #e5e7eb; border-radius: 12px; overflow: hidden; cursor: pointer; }
.progress-fill { height: 100%; background: linear-gradient(90deg, #f97316, #fb923c); border-radius: 12px; transition: width 0.4s ease; }
.progress-text { margin-top: 6px; font-size: 14px; color: #6b7280; text-align: right; font-variant-numeric: tabular-nums; }

JavaScript (on load):
const track = element.querySelector('.progress-track');
track.addEventListener('click', (e) => {
    const rect = track.getBoundingClientRect();
    const pct = Math.round(((e.clientX - rect.left) / rect.width) * 100);
    props.value = Math.max(0, Math.min(100, pct));
});

Python code:
progress = gr.HTML(
    value=65,
    label="Upload Progress",
    html_template="""
    <div class="progress-container">
        <div class="progress-label">${label}</div>
        <div class="progress-track">
            <div class="progress-fill" style="width: ${value}%"></div>
        </div>
        <div class="progress-text">${value}%</div>
    </div>
    """,
    css_template="""
    .progress-track {
        width: 100%; height: 24px;
        background: #e5e7eb; border-radius: 12px;
        overflow: hidden; cursor: pointer;
    }
    .progress-fill {
        height: 100%;
        background: linear-gradient(90deg, #f97316, #fb923c);
        border-radius: 12px; transition: width 0.4s ease;
    }
    """,
    js_on_load="""
    const track = element.querySelector('.progress-track');
    track.addEventListener('click', (e) => {
        const rect = track.getBoundingClientRect();
        const pct = Math.round(
            ((e.clientX - rect.left) / rect.width) * 100
        );
        props.value = Math.max(0, Math.min(100, pct));
    });
    """
)
Gradio custom HTML component: Colored Checkbox Group
Author: gradio
Category: input
Tags: input, checkbox, color
Description: Multi-select checkbox group with custom colors per option

Head:

HTML template:
<div class="colored-checkbox-container">
    ${label ? `<label class="container-label">${label}</label>` : ''}
    <div class="colored-checkbox-group">
        ${choices.map((choice, i) => `
            <label class="checkbox-label" data-color-index="${i}">
                <input type="checkbox" value="${choice}" ${(value || []).includes(choice) ? 'checked' : ''}>
                ${choice}
            </label>
        `).join('')}
    </div>
</div>

CSS:
.colored-checkbox-container { border: 1px solid #e5e7eb; border-radius: 12px; padding: 16px; }
.container-label { display: block; margin-bottom: 12px; font-weight: 600; }
.colored-checkbox-group { display: flex; flex-direction: column; gap: 6px; }
.checkbox-label { display: flex; align-items: center; cursor: pointer; padding: 4px 0; }
.checkbox-label input { margin-right: 8px; }
${choices.map((choice, i) => `.checkbox-label[data-color-index="${i}"] { color: ${colors[i]}; }`).join(' ')}

JavaScript (on load):
const checkboxes = element.querySelectorAll('input[type="checkbox"]');
checkboxes.forEach(checkbox => {
    checkbox.addEventListener('change', () => {
        props.value = Array.from(checkboxes)
            .filter(cb => cb.checked)
            .map(cb => cb.value);
    });
});

Python code:
class ColoredCheckboxGroup(gr.HTML):
    def __init__(self, choices, *, value=None, colors, label=None, **kwargs):
        html_template = """
        <div class="colored-checkbox-container">
            ${label ? `<label>${label}</label>` : ''}
            <div class="colored-checkbox-group">
                ${choices.map((choice, i) => `
                    <label class="checkbox-label" data-color-index="${i}">
                        <input type="checkbox" value="${choice}"
                               ${(value || []).includes(choice) ? 'checked' : ''}>
                        ${choice}
                    </label>
                `).join('')}
            </div>
        </div>
        """
        css_template = """
        .colored-checkbox-group { display: flex; flex-direction: column; gap: 6px; }
        .checkbox-label { display: flex; align-items: center; cursor: pointer; }
        ${choices.map((choice, i) =>
            `.checkbox-label[data-color-index="${i}"] { color: ${colors[i]}; }`
        ).join(' ')}
        """
        js_on_load = """
        const checkboxes = element.querySelectorAll('input[type="checkbox"]');
        checkboxes.forEach(checkbox => {
            checkbox.addEventListener('change', () => {
                props.value = Array.from(checkboxes)
                    .filter(cb => cb.checked)
                    .map(cb => cb.value);
            });
        });
        """
        super().__init__(
            value=value or [], choices=choices,
            colors=colors, label=label,
            html_template=html_template,
            css_template=css_template,
            js_on_load=js_on_load, **kwargs
        )
Gradio custom HTML component: Todo List
Author: gradio
Category: form
Tags: form, todo, checklist
Description: Interactive checklist with strikethrough on completed items

Head:

HTML template:
<h2>Todo List</h2>
<ul>
    ${value.map((item, index) => `
        <li style="text-decoration: ${completed.includes(index) ? 'line-through' : 'none'}; list-style: none; padding: 6px 0;">
            <input type="checkbox" ${completed.includes(index) ? 'checked' : ''} data-index="${index}" />
            ${item}
        </li>
    `).join('')}
</ul>

CSS:
h2 { font-size: 18px; font-weight: 700; margin-bottom: 8px; }
ul { padding: 0; margin: 0; }
li { font-size: 14px; transition: opacity 0.2s; }
li input { margin-right: 8px; cursor: pointer; }

JavaScript (on load):
const checkboxes = element.querySelectorAll('input[type="checkbox"]');
checkboxes.forEach(checkbox => {
    checkbox.addEventListener('change', () => {
        const index = parseInt(checkbox.getAttribute('data-index'));
        let completed = props.completed || [];
        if (checkbox.checked) {
            if (!completed.includes(index)) {
                completed.push(index);
            }
        } else {
            completed = completed.filter(i => i !== index);
        }
        props.completed = [...completed];
    });
});

Python code:
class TodoList(gr.HTML):
    def __init__(self, value=None, completed=None, **kwargs):
        html_template = """
        <h2>Todo List</h2>
        <ul>
            ${value.map((item, index) => `
                <li style="text-decoration: ${completed.includes(index) ? 'line-through' : 'none'};">
                    <input type="checkbox" ${completed.includes(index) ? 'checked' : ''} data-index="${index}" />
                    ${item}
                </li>
            `).join('')}
        </ul>
        """
        js_on_load = """
        const checkboxes = element.querySelectorAll('input[type="checkbox"]');
        checkboxes.forEach(checkbox => {
            checkbox.addEventListener('change', () => {
                const index = parseInt(checkbox.getAttribute('data-index'));
                let completed = props.completed || [];
                if (checkbox.checked) {
                    if (!completed.includes(index)) completed.push(index);
                } else {
                    completed = completed.filter(i => i !== index);
                }
                props.completed = [...completed];
            });
        });
        """
        super().__init__(
            value=value or [], completed=completed or [],
            html_template=html_template,
            js_on_load=js_on_load, **kwargs
        )