Aller au contenu

Tag

composant

A short label, which a button can take away.

Aperçu

Clair

Symfony
Code
<twig:Tag label="Symfony" :removable="true" name="tags[]" />

Sombre

Symfony
Code
<twig:Tag label="Symfony" :removable="true" name="tags[]" />

Essayer

Changez les propriétés ; le serveur rend l’exemple de nouveau.

Symfony
<twig:Tag label="Symfony" :removable="true" name="tags[]" />

Variantes

removable

Whether it can be taken away.

Symfony
Symfony
removable="false"
Symfony
Symfony
removable="true"

Installation

php bin/console ux:install tag --kit=github.com/parler-haut-interagir-librement/ux-kit

Propriétés

PropriétéTypePar défautDescription
removable bool false Whether it can be taken away.
name string|null null The name of a hidden field carrying the tag in a form.
value string|null null What the field and the event carry; the label when null.
removeLabel string 'Remove {label}' The name of the button, {label} replaced.

Accessibility

The button is named by removeLabel and stays hidden without a script. Once the tag is gone, the focus goes to the tag beside it, or to the list. tag:remove can be cancelled, for a server to answer first.

Fichiers à copier

assets/controllers/tag_controller.js
import { Controller } from '@hotwired/stimulus';

/*
 * The button that takes a tag away. The event `tag:remove` can be cancelled, for a server to answer first. The focus
 * goes to the tag beside it, or to the list once the last one is gone.
 */
export default class extends Controller {
    static targets = ['remove'];

    static values = { name: String };

    connect() {
        this.removeTarget.hidden = false;
    }

    remove() {
        const event = this.dispatch('remove', { cancelable: true, detail: { name: this.nameValue } });

        if (event.defaultPrevented) {
            return;
        }

        const parent = this.element.parentElement;
        const beside = this.#button(this.element.nextElementSibling) ?? this.#button(this.element.previousElementSibling);

        this.element.remove();

        if (beside) {
            beside.focus();
        } else if (parent) {
            parent.tabIndex = -1;
            parent.focus();
        }
    }

    #button(tag) {
        return tag?.querySelector(`[data-${this.identifier}-target~="remove"]`) ?? null;
    }
}
templates/components/Tag.html.twig
{#-
 # A short label, which a button can take away once a script runs. The event `tag:remove` can be cancelled; the focus
 # goes to the tag beside it.
 #}
{%- props
    ## string What the tag says.
    label,
    ## bool Whether it can be taken away.
    removable = false,
    ## string|null The name of a hidden field carrying the tag in a form.
    name = null,
    ## string|null What the field and the event carry; the label when null.
    value = null,
    ## string The name of the button, `{label}` replaced.
    removeLabel = 'Remove {label}'
-%}
<span{{ attributes.defaults({class: 'isTag'}|merge(removable ? {'data-controller': 'tag', 'data-tag-name-value': value ?? label} : {})) }}>
    <span class="isTagLabel">{{ label }}</span>
    {%- if name is not null -%}<input type="hidden" name="{{ name }}" value="{{ value ?? label }}">{%- endif -%}
    {%- if removable -%}<button type="button" class="isTagRemove" hidden aria-label="{{ removeLabel|replace({'{label}': label}) }}" data-tag-target="remove" data-action="tag#remove"><span aria-hidden="true">&times;</span></button>{%- endif -%}
</span>