Links vom Tabulator nicht beachten
bearbeitet von
@@MH
> Ich hab mal ein Bild von dem Formular gemacht:
OK, eine Gruppe mit zwei Eingabefeldern und einem Zeile-löschen-Button (ich würde das eher als „diese *Person* löschen“ bezeichnen). Eingabefelder werden mit `fieldset` gruppiert:
~~~HTML
<fieldset>
<legend>Person hinzufügen</legend>
<div>
<label>
Vorname
<input name="givenName[]"/>
</label>
<label>
Nachname
<input name="familyName[]"/>
</label>
<button class="control-delete-person" type="button" hidden="">diese Person löschen</button>
</div>
</fieldset>
~~~
Davon kann es später mehrere geben (deshalb `class`, nicht `id`), wenn welche mit JavaScript hinzugefügt werden. Dazu gibt es einen Zeile-hinzufügen-Button (den ich lieber „weitere *Person* hinzufügen“ beschriften würde) und einen Submit-Button fürs Formular. Da die Buttons ohne JavaScript nutzlos sind, sind sie erstmal per `hidden`-Attribut versteckt, bis das JavaScript ausgeführt wird.
~~~HTML
<form>
<fieldset>
<legend>Person hinzufügen</legend>
<div>
<label>
Vorname
<input name="givenName[]"/>
</label>
<label>
Nachname
<input name="familyName[]"/>
</label>
<button class="control-delete-person" type="button" hidden="">diese Person löschen</button>
</div>
</fieldset>
<p>
<button id="control-add-person" type="button" hidden="">weitere Person hinzufügen</button>
</p>
<p>
<button type="submit">abschicken</button>
</p>
</form>
~~~
Das JavaScript entfernt dann als erstes das `hidden` und macht die Buttons sichtbar:
~~~JavaScript
const formElement = document.querySelector('form');
const firstFieldsetElement = formElement.querySelector('fieldset');
const firstPElement = formElement.querySelector('p');
formElement.querySelectorAll('button[hidden]').forEach(element => {
element.hidden = false;
});
~~~
Die Buttons bekommen ihre Funktion – per *event delegation*{:@en}: es wird auf `click`-Evemts fürs ganze Formular gelauscht und im Eventhandler wird geprüft, ob das `click` durch einen Button ausgelöst wurde und wenn ja, durch welchen. Dadurch muss man bei den später hinzukommenden Buttons nicht noch Eventhandler registrieren.
~~~JavaScript
formElement.addEventListener('click', event => {
if (event.target.id == 'control-add-person')
{
// füge Eingabefelder für weitere Person hinzu
}
else if (event.target.classList.contains('control-delete-person'))
{
// enferne Eingabefelder für diese Person
}
});
~~~
Um Eingabefelder für weitere Person hinzuzufügen, wird das `fieldset` geklont. Die dabei mit geklonten Werte der Eingabefelder müssen gelöscht werden. Außerdem wird der Fokus auf die neu eingefügte Gruppe gelegt, welches deshalb `tabIndex` −1 hat. (Vielleicht wäre es sogar besser, gleich das erste Eingabefeld in der Gruppe zu fokussieren – mal jemanden fragen, der sich damit auskennt.)
~~~JavaScript
if (event.target.id == 'control-add-person')
{
const clone = document.importNode(firstFieldsetElement, true);
clone.querySelectorAll('input').forEach(element => {
element.value = null;
});
formElement.insertBefore(clone, firstPElement);
clone.tabIndex = -1;
clone.focus();
}
~~~
Beim Entfernen wird das zu dem auslösenden Button gehörige `fieldset`-Element ermittelt und aus dem DOM entfernt.
~~~JavaScript
else if (event.target.classList.contains('control-delete-person'))
{
formElement.removeChild(event.target.closest('fieldset'));
}
~~~
Per CSS werden die für die für die visuelle Darstellung nicht benötigten Beschriftungen *visuell* versteckt – aber so, dass sie von Screenreadern immer noch vorgelesen werden, also nicht `display: none` oder `visibility: hidden`. Das betrifft die `legend`-Elemente, die Beschriftungen der Eingabefelder außer denen in der ersten Gruppe und die Person-löschen-Buttons, die durch ❌ visuell repräsentiert werden.
~~~CSS
legend,
fieldset:not(:first-child) label,
.control-delete-person
{
font-size: 0;
}
~~~
Das Ganze ist in [diesem Codepen](https://codepen.io/gunnarbittersmann/pen/ppjaam) zu sehen.
Man könnte den Fokus von `fieldset` auch durch eine Hintergrundfarbe visualisieren und dann die `outline` entfernen (im Pen auskommentiert).
~~~CSS
fieldset:focus
{
background: #eef;
outline: none;
}
fieldset:focus-within
{
background: #eef;
}
Und wenn man will, die `:focus`-Effekte auch für `:hover` angeben …
LLAP 🖖
--
“When UX doesn’t consider *all* users, shouldn’t it be known as ‘*Some* User Experience’ or... SUX? #a11y” —[Billy Gregory](https://twitter.com/thebillygregory/status/552466012713783297)
> Ich hab mal ein Bild von dem Formular gemacht:
OK, eine Gruppe mit zwei Eingabefeldern und einem Zeile-löschen-Button (ich würde das eher als „diese *Person* löschen“ bezeichnen). Eingabefelder werden mit `fieldset` gruppiert:
~~~HTML
<fieldset>
<legend>Person hinzufügen</legend>
<div>
<label>
Vorname
<input name="givenName[]"/>
</label>
<label>
Nachname
<input name="familyName[]"/>
</label>
<button class="control-delete-person" type="button" hidden="">diese Person löschen</button>
</div>
</fieldset>
~~~
Davon kann es später mehrere geben (deshalb `class`, nicht `id`), wenn welche mit JavaScript hinzugefügt werden. Dazu gibt es einen Zeile-hinzufügen-Button (den ich lieber „weitere *Person* hinzufügen“ beschriften würde) und einen Submit-Button fürs Formular. Da die Buttons ohne JavaScript nutzlos sind, sind sie erstmal per `hidden`-Attribut versteckt, bis das JavaScript ausgeführt wird.
~~~HTML
<form>
<fieldset>
<legend>Person hinzufügen</legend>
<div>
<label>
Vorname
<input name="givenName[]"/>
</label>
<label>
Nachname
<input name="familyName[]"/>
</label>
<button class="control-delete-person" type="button" hidden="">diese Person löschen</button>
</div>
</fieldset>
<p>
<button id="control-add-person" type="button" hidden="">weitere Person hinzufügen</button>
</p>
<p>
<button type="submit">abschicken</button>
</p>
</form>
~~~
Das JavaScript entfernt dann als erstes das `hidden` und macht die Buttons sichtbar:
~~~JavaScript
const formElement = document.querySelector('form');
const firstFieldsetElement = formElement.querySelector('fieldset');
const firstPElement = formElement.querySelector('p');
formElement.querySelectorAll('button[hidden]').forEach(element => {
element.hidden = false;
});
~~~
Die Buttons bekommen ihre Funktion – per *event delegation*{:@en}: es wird auf `click`-Evemts fürs ganze Formular gelauscht und im Eventhandler wird geprüft, ob das `click` durch einen Button ausgelöst wurde und wenn ja, durch welchen. Dadurch muss man bei den später hinzukommenden Buttons nicht noch Eventhandler registrieren.
~~~JavaSc
formElement.addEventListener('click', event => {
if (event.target.id == 'control-add-person')
{
// füge Eingabefelder für weitere Person hinzu
}
else if (event.target.classList.contains('control-delete-person'))
{
// enferne Eingabefelder für diese Person
}
});
~~~
Um Eingabefelder für weitere Person hinzuzufügen, wird das `fieldset` geklont. Die dabei mit geklonten Werte der Eingabefelder müssen gelöscht werden. Außerdem wird der Fokus auf die neu eingefügte Gruppe gelegt, welches deshalb `tabIndex` −1 hat. (Vielleicht wäre es sogar besser, gleich das erste Eingabefeld in der Gruppe zu fokussieren – mal jemanden fragen, der sich damit auskennt.)
~~~JavaSc
if (event.target.id == 'control-add-person')
{
const clone = document.importNode(firstFieldsetElement, true);
clone.querySelectorAll('input').forEach(element => {
element.value = null;
});
formElement.insertBefore(clone, firstPElement);
clone.tabIndex = -1;
clone.focus();
}
~~~
Beim Entfernen wird das zu dem auslösenden Button gehörige `fieldset`-Element ermittelt und aus dem DOM entfernt.
~~~JavaSc
else if (event.target.classList.contains('control-delete-person'))
{
formElement.removeChild(event.target.closest('fieldset'));
}
~~~
Per CSS werden die für die für die visuelle Darstellung nicht benötigten Beschriftungen *visuell* versteckt – aber so, dass sie von Screenreadern immer noch vorgelesen werden, also nicht `display: none` oder `visibility: hidden`. Das betrifft die `legend`-Elemente, die Beschriftungen der Eingabefelder außer denen in der ersten Gruppe und die Person-löschen-Buttons, die durch ❌ visuell repräsentiert werden.
~~~CSS
legend,
fieldset:not(:first-child) label,
.control-delete-person
{
font-size: 0;
}
~~~
Das Ganze ist in [diesem Codepen](https://codepen.io/gunnarbittersmann/pen/ppjaam) zu sehen.
Man könnte den Fokus von `fieldset` auch durch eine Hintergrundfarbe visualisieren und dann die `outline` entfernen (im Pen auskommentiert).
~~~CSS
fieldset:focus
{
background: #eef;
outline: none;
}
fieldset:focus-within
{
background: #eef;
}
Und wenn man will, die `:focus`-Effekte auch für `:hover` angeben …
LLAP 🖖
--
“When UX doesn’t consider *all* users, shouldn’t it be known as ‘*Some* User Experience’ or... SUX? #a11y” —[Billy Gregory](https://twitter.com/thebillygregory/status/552466012713783297)
Links vom Tabulator nicht beachten
bearbeitet von
@@MH
> Ich hab mal ein Bild von dem Formular gemacht:
OK, eine Gruppe mit zwei Eingabefeldern und einem Zeile-löschen-Button (ich würde das eher als „diese *Person* löschen“ bezeichnen). Eingabefelder werden mit `fieldset` gruppiert:
~~~HTML
<fieldset>
<legend>Person hinzufügen</legend>
<div>
<label>
Vorname
<input name="givenName[]"/>
</label>
<label>
Nachname
<input name="familyName[]"/>
</label>
<button class="control-delete-person" type="button" hidden="">diese Person löschen</button>
</div>
</fieldset>
~~~
Davon kann es später mehrere geben (deshalb `class`, nicht `id`), wenn welche mit JavaScript hinzugefügt werden. Dazu gibt es einen Zeile-hinzufügen-Button (den ich lieber „weitere *Person* hinzufügen“ beschriften würde) und einen Submit-Button fürs Formular. Da die Buttons ohne JavaScript nutzlos sind, sind sie erstmal per `hidden`-Attribut versteckt, bis das JavaScript ausgeführt wird.
~~~HTML
<form>
<fieldset>
<legend>Person hinzufügen</legend>
<div>
<label>
Vorname
<input name="givenName[]"/>
</label>
<label>
Nachname
<input name="familyName[]"/>
</label>
<button class="control-delete-person" type="button" hidden="">diese Person löschen</button>
</div>
</fieldset>
<p>
<button id="control-add-person" type="button" hidden="">weitere Person hinzufügen</button>
</p>
<p>
<button type="submit">abschicken</button>
</p>
</form>
~~~
Das JavaScipt entfernt dann als erstes das `hidden` und macht die Buttons sichtbar:
~~~JavaScipt
const formElement = document.querySelector('form');
const firstFieldsetElement = formElement.querySelector('fieldset');
const firstPElement = formElement.querySelector('p');
formElement.querySelectorAll('button[hidden]').forEach(element => {
element.hidden = false;
});
~~~
Die Buttons bekommen ihre Funktion – per *event delegation*{:@en}: es wird auf `click`-Evemts fürs ganze Formular gelauscht und im Eventhandler wird geprüft, ob das `click` durch einen Button ausgelöst wurde und wenn ja, durch welchen. Dadurch muss man bei den später hinzukommenden Buttons nicht noch Eventhandler registrieren.
~~~JavaScipt
formElement.addEventListener('click', event => {
if (event.target.id == 'control-add-person')
{
// füge Eingabefelder für weitere Person hinzu
}
else if (event.target.classList.contains('control-delete-person'))
{
// enferne Eingabefelder für diese Person
}
});
~~~
Um Eingabefelder für weitere Person hinzuzufügen, wird das `fieldset` geklont. Die dabei mit geklonten Werte der Eingabefelder müssen gelöscht werden. Außerdem wird der Fokus auf die neu eingefügte Gruppe gelegt, welches deshalb `tabIndex` −1 hat. (Vielleicht wäre es sogar besser, gleich das erste Eingabefeld in der Gruppe zu fokussieren – mal jemanden fragen, der sich damit auskennt.)
~~~JavaScipt
if (event.target.id == 'control-add-person')
{
const clone = document.importNode(firstFieldsetElement, true);
clone.querySelectorAll('input').forEach(element => {
element.value = null;
});
formElement.insertBefore(clone, firstPElement);
clone.tabIndex = -1;
clone.focus();
}
~~~
Beim Entfernen wird das zu dem auslösenden Button gehörige `fieldset`-Element ermittelt und aus dem DOM entfernt.
~~~JavaScipt
else if (event.target.classList.contains('control-delete-person'))
{
formElement.removeChild(event.target.closest('fieldset'));
}
~~~
Per CSS werden die für die für die visuelle Darstellung nicht benötigten Beschriftungen *visuell* versteckt – aber so, dass sie von Screenreadern immer noch vorgelesen werden, also nicht `display: none` oder `visibility: hidden`. Das betrifft die `legend`-Elemente, die Beschriftungen der Eingabefelder außer denen in der ersten Gruppe und die Person-löschen-Buttons, die durch ❌ visuell repräsentiert werden.
~~~CSS
legend,
fieldset:not(:first-child) label,
.control-delete-person
{
font-size: 0;
}
~~~
Das Ganze ist in [diesem Codepen](https://codepen.io/gunnarbittersmann/pen/ppjaam) zu sehen.
Man könnte den Fokus von `fieldset` auch durch eine Hintergrundfarbe visualisieren und dann die `outline` entfernen (im Pen auskommentiert).
~~~CSS
fieldset:focus
{
background: #eef;
outline: none;
}
fieldset:focus-within
{
background: #eef;
}
Und wenn man will, die `:focus`-Effekte auch für `:hover` angeben …
LLAP 🖖
--
“When UX doesn’t consider *all* users, shouldn’t it be known as ‘*Some* User Experience’ or... SUX? #a11y” —[Billy Gregory](https://twitter.com/thebillygregory/status/552466012713783297)
> Ich hab mal ein Bild von dem Formular gemacht:
OK, eine Gruppe mit zwei Eingabefeldern und einem Zeile-löschen-Button (ich würde das eher als „diese *Person* löschen“ bezeichnen). Eingabefelder werden mit `fieldset` gruppiert:
~~~HTML
<fieldset>
<legend>Person hinzufügen</legend>
<div>
<label>
Vorname
<input name="givenName[]"/>
</label>
<label>
Nachname
<input name="familyName[]"/>
</label>
<button class="control-delete-person" type="button" hidden="">diese Person löschen</button>
</div>
</fieldset>
~~~
Davon kann es später mehrere geben (deshalb `class`, nicht `id`), wenn welche mit JavaScript hinzugefügt werden. Dazu gibt es einen Zeile-hinzufügen-Button (den ich lieber „weitere *Person* hinzufügen“ beschriften würde) und einen Submit-Button fürs Formular. Da die Buttons ohne JavaScript nutzlos sind, sind sie erstmal per `hidden`-Attribut versteckt, bis das JavaScript ausgeführt wird.
~~~HTML
<form>
<fieldset>
<legend>Person hinzufügen</legend>
<div>
<label>
Vorname
<input name="givenName[]"/>
</label>
<label>
Nachname
<input name="familyName[]"/>
</label>
<button class="control-delete-person" type="button" hidden="">diese Person löschen</button>
</div>
</fieldset>
<p>
<button id="control-add-person" type="button" hidden="">weitere Person hinzufügen</button>
</p>
<p>
<button type="submit">abschicken</button>
</p>
</form>
~~~
Das JavaScipt entfernt dann als erstes das `hidden` und macht die Buttons sichtbar:
~~~JavaScipt
const formElement = document.querySelector('form');
const firstFieldsetElement = formElement.querySelector('fieldset');
const firstPElement = formElement.querySelector('p');
formElement.querySelectorAll('button[hidden]').forEach(element => {
element.hidden = false;
});
~~~
Die Buttons bekommen ihre Funktion – per *event delegation*{:@en}: es wird auf `click`-Evemts fürs ganze Formular gelauscht und im Eventhandler wird geprüft, ob das `click` durch einen Button ausgelöst wurde und wenn ja, durch welchen. Dadurch muss man bei den später hinzukommenden Buttons nicht noch Eventhandler registrieren.
~~~JavaScipt
formElement.addEventListener('click', event => {
if (event.target.id == 'control-add-person')
{
// füge Eingabefelder für weitere Person hinzu
}
else if (event.target.classList.contains('control-delete-person'))
{
// enferne Eingabefelder für diese Person
}
});
~~~
Um Eingabefelder für weitere Person hinzuzufügen, wird das `fieldset` geklont. Die dabei mit geklonten Werte der Eingabefelder müssen gelöscht werden. Außerdem wird der Fokus auf die neu eingefügte Gruppe gelegt, welches deshalb `tabIndex` −1 hat. (Vielleicht wäre es sogar besser, gleich das erste Eingabefeld in der Gruppe zu fokussieren – mal jemanden fragen, der sich damit auskennt.)
~~~JavaScipt
if (event.target.id == 'control-add-person')
{
const clone = document.importNode(firstFieldsetElement, true);
clone.querySelectorAll('input').forEach(element => {
element.value = null;
});
formElement.insertBefore(clone, firstPElement);
clone.tabIndex = -1;
clone.focus();
}
~~~
Beim Entfernen wird das zu dem auslösenden Button gehörige `fieldset`-Element ermittelt und aus dem DOM entfernt.
~~~JavaScipt
else if (event.target.classList.contains('control-delete-person'))
{
formElement.removeChild(event.target.closest('fieldset'));
}
~~~
Per CSS werden die für die für die visuelle Darstellung nicht benötigten Beschriftungen *visuell* versteckt – aber so, dass sie von Screenreadern immer noch vorgelesen werden, also nicht `display: none` oder `visibility: hidden`. Das betrifft die `legend`-Elemente, die Beschriftungen der Eingabefelder außer denen in der ersten Gruppe und die Person-löschen-Buttons, die durch ❌ visuell repräsentiert werden.
~~~CSS
legend,
fieldset:not(:first-child) label,
.control-delete-person
{
font-size: 0;
}
~~~
Das Ganze ist in [diesem Codepen](https://codepen.io/gunnarbittersmann/pen/ppjaam) zu sehen.
Man könnte den Fokus von `fieldset` auch durch eine Hintergrundfarbe visualisieren und dann die `outline` entfernen (im Pen auskommentiert).
~~~CSS
fieldset:focus
{
background: #eef;
outline: none;
}
fieldset:focus-within
{
background: #eef;
}
Und wenn man will, die `:focus`-Effekte auch für `:hover` angeben …
LLAP 🖖
--
“When UX doesn’t consider *all* users, shouldn’t it be known as ‘*Some* User Experience’ or... SUX? #a11y” —[Billy Gregory](https://twitter.com/thebillygregory/status/552466012713783297)
Links vom Tabulator nicht beachten
bearbeitet von
@@MH
> Ich hab mal ein Bild von dem Formular gemacht:
OK, eine Gruppe mit zwei Eingabefeldern und einem Zeile-löschen-Button (ich würde das eher als „diese *Person* löschen“ bezeichnen). Eingabefelder werden mit `fieldset` gruppiert:
~~~HTML
<fieldset>
<legend>Person hinzufügen</legend>
<div>
<label>
Vorname
<input name="givenName[]"/>
</label>
<label>
Nachname
<input name="familyName[]"/>
</label>
<button class="control-delete-person" type="button" hidden="">diese Person löschen</button>
</div>
</fieldset>
~~~
Davon kann es später mehrere geben (deshalb `class`, nicht `id`), wenn welche mit JavaScript hinzugefügt werden. Dazu gibt es einen Zeile-hinzufügen-Button (den ich lieber „weitere *Person* hinzufügen“ beschriften würde) und einen Submit-Button fürs Formular. Da die Buttons ohne JavaScript nutzlos sind, sind sie erstmal per `hidden`-Attribut versteckt, bis das JavaScript ausgeführt wird.
~~~HTML
<form>
<fieldset>
<legend>Person hinzufügen</legend>
<div>
<label>
Vorname
<input name="givenName[]"/>
</label>
<label>
Nachname
<input name="familyName[]"/>
</label>
<button class="control-delete-person" type="button" hidden="">diese Person löschen</button>
</div>
</fieldset>
<p>
<button id="control-add-person" type="button" hidden="">weitere Person hinzufügen</button>
</p>
<p>
<button type="submit">abschicken</button>
</p>
</form>
~~~
LLAP 🖖
--
“When UX doesn’t consider *all* users, shouldn’t it be known as ‘*Some* User Experience’ or... SUX? #a11y” —[Billy Gregory](https://twitter.com/thebillygregory/status/552466012713783297)