Build an Accessible Tablist
Are you in the right place? If you are constrained to a third-party component library, see the Tab Accessibility Checklist and ensure that it passes. Otherwise, follow the guidance here to choose the best option for your project.
Use the NYSDS Tab Web Component
The NYSDS Tab is a web component you can drop into your project and use right away. For most teams, this is the simplest way to achieve an accessible component. This means teams don’t need to manually implement accessibility or test for it.
What's already handled for you:-
Keyboard Navigation
Tab, Enter, Space, and Arrows work as intended
-
Screen reader support
Tested with NVDA, JAWS, and VoiceOver
-
Focus management
Focus stays where users expect it
-
Voice control
Supports Windows and macOS
-
Zoom magnification
Works correctly at 200% browser zoom
-
WCAG 2.2 AA conformant
Meets New York State standards
Alternatives
For projects not ready to adopt the Design System Whether you seek to remediate an existing component or build one from scratch, these reference implementations will ensure an accessible outcome. For more details, read about this pattern.
Custom Tablist (first demo)
When to use If your team has source-level control over UI code, and either can't use Web Components or have a pressing need for unique functionality not provided by the NYSDS Tab component, you may choose to build a custom tablist. Or perhaps your legacy component has been flagged for remediation and you need a high quality reference.
How is it different This tablist expresses the look-and-feel of the design system with many aspects modeled after the NYSDS Tab component. The ways in which it differs show how to honor the spirit of the design system when alternative accessible interaction and layout features are implemented. Specifically, when tab headers scroll horizontally, this tablist shows scroll buttons with large, generous targets to ease use with touch interfaces (such as tablets) and pointing devices (such as mice) by people with motor disabilities.
About the first demo On this page there are two demos of the same component. This first demo has limited content and thus appears simple.
-
In this demo the tabset gains its accessible name by being
aria-labelledbytheh4heading above it -
The scroll buttons, which will not appear in this example,
are nevertheless
aria-describedbythe same heading - The tabset has an optional, custom CSS class to set its height and margin
Some notable 20th-century French classical composers
Georges Auric (15 February 1899 – 23 July 1983) was a French composer, born in Lodève, Hérault, France. He was considered one of Les Six—The Group of Six—a group of artists informally associated with Jean Cocteau and Erik Satie. Before he turned 20 he had orchestrated and written incidental music for several ballets and stage productions. He also had a long and distinguished career as a film composer.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In sit amet massa auctor quam viverra malesuada. Maecenas eu lorem a ex ullamcorper rhoncus non vitae eros. Morbi tincidunt egestas lacus, eget consectetur nibh vestibulum aliquam. Nulla erat quam, hendrerit id congue suscipit, luctus ultricies urna. Nullam erat nisl, posuere id blandit non, porta eget justo. Integer faucibus sem ac maximus auctor. Aliquam et orci tempus, volutpat nisl sed, rhoncus eros. Praesent egestas felis risus, id feugiat purus ullamcorper a. Nunc malesuada, erat sit amet interdum fringilla, magna est iaculis diam, vitae vehicula mi elit eu erat. Praesent congue tortor ultrices, sagittis risus eget, suscipit orci. Vivamus eu vestibulum mauris. Suspendisse vel diam mauris. Sed ante enim, eleifend vel quam in, dignissim porttitor ipsum. Nunc suscipit felis nec elit blandit sollicitudin.
Vivamus ac porttitor risus. Nulla convallis, libero at consectetur viverra, nulla dolor tempus ipsum, quis iaculis orci lacus quis ex. Fusce ac turpis vehicula, efficitur quam sit amet, tristique lectus. Duis quis semper lectus. Vestibulum semper ligula et congue vestibulum. Quisque laoreet lacinia sapien ut faucibus. Suspendisse id molestie lectus. Etiam faucibus nec lacus sit amet egestas. Mauris quis congue mi, posuere pellentesque dolor. Mauris eget sodales nibh. Vestibulum ultrices quam id finibus euismod. Curabitur eleifend lorem non fringilla feugiat.
Maecenas efficitur et lorem sit amet bibendum. Sed a molestie odio, nec iaculis velit. Duis ut porta quam. Etiam aliquam fermentum erat, sed consequat neque viverra quis. Etiam vitae ante consequat, pretium nulla et, tempus risus. Cras eleifend ex mauris, sit amet faucibus velit fermentum vel. Integer malesuada, sapien vitae pellentesque lobortis, erat ligula viverra tellus, quis scelerisque nunc risus nec arcu. Quisque tincidunt tempor risus ac pulvinar. Aenean efficitur massa eu leo iaculis sagittis in sit amet velit. Sed egestas enim efficitur, facilisis tortor varius, fringilla tellus. Morbi pellentesque eleifend nulla, in malesuada sapien molestie id. Cras pharetra erat lectus, at mattis arcu imperdiet eget.
Aliquam ullamcorper mauris ut scelerisque ultrices. Maecenas dapibus, elit vitae interdum finibus, ligula velit interdum enim, id iaculis quam tortor non justo. In dapibus elit sed dolor tempus tempus. Quisque nunc nisi, suscipit a tellus a, accumsan varius arcu. Morbi interdum erat non auctor tempus. Praesent viverra dolor vel rutrum semper. Suspendisse iaculis massa sit amet mauris commodo faucibus. Etiam tempor velit dolor, vitae lobortis sem lacinia at. Nam viverra sapien eget mi suscipit tincidunt sed semper sapien. Maecenas ut turpis eu ligula ultrices dapibus. Nullam facilisis ipsum vitae rutrum laoreet. Donec euismod pretium tempor. Nullam velit ex, ullamcorper in consectetur ut, accumsan ac nulla. Suspendisse sem velit, elementum vitae leo et, suscipit volutpat urna.
Proin mattis eros vel nulla dapibus, id placerat tortor convallis. In a velit vel ex vestibulum egestas quis sed massa. Vestibulum eu nibh vel ex bibendum consectetur. Quisque sed purus ut mauris gravida bibendum. Ut dui nibh, volutpat nec tincidunt sed, laoreet vel purus. Vestibulum varius purus in justo laoreet, eu scelerisque tortor mollis. Proin efficitur ullamcorper magna, at finibus nisl fringilla id. Vivamus viverra vulputate quam sed aliquam. Nullam massa quam, viverra eget dictum vel, cursus vitae libero. Morbi lacinia, nisi quis blandit tristique, urna ex volutpat lectus, eget rutrum libero dolor ut arcu. Cras porta purus ac convallis mattis.
Claude Debussy (22 August 1862 – 25 March 1918) was a French composer. He is sometimes seen as the first Impressionist composer, although he vigorously rejected the term. He was among the most influential composers of the late 19th and early 20th centuries.
Gabriel Fauré (12 May 1845 – 4 November 1924) was a French composer, organist, pianist and teacher. He was one of the foremost French composers of his generation, and his musical style influenced many 20th-century composers. Among his best-known works are his Pavane, Requiem, Sicilienne, nocturnes for piano and the songs "Après un rêve" and "Clair de lune". Although his best-known and most accessible compositions are generally his earlier ones, Fauré composed many of his most highly regarded works in his later years, in a more harmonically and melodically complex style.
<style>
.tab-custom-1 {
height: 360px;
margin-block-end: 2rem;
}
</style>
<h4 id="Tab1Title">
Some notable 20th-century French classical composers
</h4>
<div
aria-labelledby="Tab1Title"
class="nysa11y tablist tab-custom-1"
data-component="tablist"
data-html="custom"
role="tablist">
<div data-part="tabs">
<div data-part="scrollButtons">
<button aria-describedby="Tab1Title" data-scroll="to-start" type="button">
<span class="sr-only">visual scroll toward start</span>
</button>
<button aria-describedby="Tab1Title" data-scroll="to-end" type="button">
<span class="sr-only">visual scroll toward end</span>
</button>
</div>
<div data-part="tabsEnclosure">
<!-- ==================================== -->
<i class="tabs__scroll-affordance-start"></i>
<!-- ==================================== -->
<div data-part="scrollContainer">
<!-- ======================== -->
<s data-part="sentinelStart"></s>
<!-- ======================== -->
<!-- //////// Tab state and associations.
| ---------------------------------------
| role="tab" REQUIRED: hardcode
| aria-controls="" Managed by JavaScript
| aria-selected="" Managed by JavaScript
| id="" Managed by JavaScript
| tabindex="" Managed by JavaScript
| type="button" Recommended: hardcode
| ---------------------------------------
| Inspect with DevTools. \\\\\\\\\\\\ -->
<button
role="tab"
aria-controls=""
aria-selected=""
id=""
tabindex=""
type="button"
lang="fr">Georges Auric</button>
<button
role="tab"
aria-controls=""
aria-selected=""
id=""
tabindex=""
type="button"
lang="fr">Claude Debussy</button>
<button
role="tab"
aria-controls=""
aria-selected=""
id=""
tabindex=""
type="button"
lang="fr">Gabriel Fauré</button>
<!-- ====================== -->
<s data-part="sentinelEnd"></s>
<!-- ====================== -->
</div>
<!-- ================================== -->
<i class="tabs__scroll-affordance-end"></i>
<!-- ================================== -->
</div>
</div>
<div data-part="tabpanels" tabindex="0">
<!-- ///// Tabpanel state and associations.
| -----------------------------------------
| role="tabpanel" REQUIRED: hardcode
| aria-labelledby="" Managed by JavaScript
| id="" Managed by JavaScript
| hidden Managed by JavaScript
| -----------------------------------------
| Inspect with DevTools. \\\\\\\\\\\\\\ -->
<div
role="tabpanel"
aria-labelledby=""
id=""
>
<p>
<a
href="https://en.wikipedia.org/wiki/Georges_Auric"
lang="fr">Georges Auric</a>
(15 February 1899 – 23 July 1983) was a French
composer, born in
<span lang="fr">Lodève, Hérault,</span> France. He
was considered one of
<span lang="fr">Les Six</span>—The Group of Six—a
group of artists informally associated with
<span lang="fr">Jean Cocteau</span> and
<span lang="fr">Erik Satie</span>. Before he turned
20 he had orchestrated and written incidental music
for several ballets and stage productions. He also
had a long and distinguished career as a film
composer.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing
elit. In sit amet massa auctor quam viverra
malesuada. Maecenas eu lorem a ex ullamcorper
rhoncus non vitae eros. Morbi tincidunt egestas
lacus, eget consectetur nibh vestibulum aliquam.
Nulla erat quam, hendrerit id congue suscipit,
luctus ultricies urna. Nullam erat nisl, posuere id
blandit non, porta eget justo. Integer faucibus sem
ac maximus auctor. Aliquam et orci tempus, volutpat
nisl sed, rhoncus eros. Praesent egestas felis
risus, id feugiat purus ullamcorper a. Nunc
malesuada, erat sit amet interdum fringilla, magna
est iaculis diam, vitae vehicula mi elit eu erat.
Praesent congue tortor ultrices, sagittis risus
eget, suscipit orci. Vivamus eu vestibulum mauris.
Suspendisse vel diam mauris. Sed ante enim, eleifend
vel quam in, dignissim porttitor ipsum. Nunc
suscipit felis nec elit blandit sollicitudin.
</p>
<p>
Vivamus ac porttitor risus. Nulla convallis, libero
at consectetur viverra, nulla dolor tempus ipsum,
quis iaculis orci lacus quis ex. Fusce ac turpis
vehicula, efficitur quam sit amet, tristique lectus.
Duis quis semper lectus. Vestibulum semper ligula et
congue vestibulum. Quisque laoreet lacinia sapien ut
faucibus. Suspendisse id molestie lectus. Etiam
faucibus nec lacus sit amet egestas. Mauris quis
congue mi, posuere pellentesque dolor. Mauris eget
sodales nibh. Vestibulum ultrices quam id finibus
euismod. Curabitur eleifend lorem non fringilla
feugiat.
</p>
<p>
Maecenas efficitur et lorem sit amet bibendum. Sed a
molestie odio, nec iaculis velit. Duis ut porta
quam. Etiam aliquam fermentum erat, sed consequat
neque viverra quis. Etiam vitae ante consequat,
pretium nulla et, tempus risus. Cras eleifend ex
mauris, sit amet faucibus velit fermentum vel.
Integer malesuada, sapien vitae pellentesque
lobortis, erat ligula viverra tellus, quis
scelerisque nunc risus nec arcu. Quisque tincidunt
tempor risus ac pulvinar. Aenean efficitur massa eu
leo iaculis sagittis in sit amet velit. Sed egestas
enim efficitur, facilisis tortor varius, fringilla
tellus. Morbi pellentesque eleifend nulla, in
malesuada sapien molestie id. Cras pharetra erat
lectus, at mattis arcu imperdiet eget.
</p>
<p>
Aliquam ullamcorper mauris ut scelerisque ultrices.
Maecenas dapibus, elit vitae interdum finibus,
ligula velit interdum enim, id iaculis quam tortor
non justo. In dapibus elit sed dolor tempus tempus.
Quisque nunc nisi, suscipit a tellus a, accumsan
varius arcu. Morbi interdum erat non auctor tempus.
Praesent viverra dolor vel rutrum semper.
Suspendisse iaculis massa sit amet mauris commodo
faucibus. Etiam tempor velit dolor, vitae lobortis
sem lacinia at. Nam viverra sapien eget mi suscipit
tincidunt sed semper sapien. Maecenas ut turpis eu
ligula ultrices dapibus. Nullam facilisis ipsum
vitae rutrum laoreet. Donec euismod pretium tempor.
Nullam velit ex, ullamcorper in consectetur ut,
accumsan ac nulla. Suspendisse sem velit, elementum
vitae leo et, suscipit volutpat urna.
</p>
<p>
Proin mattis eros vel nulla dapibus, id placerat
tortor convallis. In a velit vel ex vestibulum
egestas quis sed massa. Vestibulum eu nibh vel ex
bibendum consectetur. Quisque sed purus ut mauris
gravida bibendum. Ut dui nibh, volutpat nec
tincidunt sed, laoreet vel purus. Vestibulum varius
purus in justo laoreet, eu scelerisque tortor
mollis. Proin efficitur ullamcorper magna, at
finibus nisl fringilla id. Vivamus viverra vulputate
quam sed aliquam. Nullam massa quam, viverra eget
dictum vel, cursus vitae libero. Morbi lacinia, nisi
quis blandit tristique, urna ex volutpat lectus,
eget rutrum libero dolor ut arcu. Cras porta purus
ac convallis mattis.
</p>
</div>
<div
role="tabpanel"
aria-labelledby=""
id=""
hidden
>
<p>
<a
href="https://en.wikipedia.org/wiki/Claude_Debussy"
lang="fr">Claude Debussy</a>
(22 August 1862 – 25 March 1918) was a French
composer. He is sometimes seen as the first
Impressionist composer, although he vigorously
rejected the term. He was among the most influential
composers of the late 19th and early 20th centuries.
</p>
</div>
<div
role="tabpanel"
aria-labelledby=""
id=""
hidden
>
<p>
<a
href="https://en.wikipedia.org/wiki/Gabriel_Fauré"
lang="fr">Gabriel Fauré</a>
(12 May 1845 – 4 November 1924) was a French
composer, organist, pianist and teacher. He was one
of the foremost French composers of his generation,
and his musical style influenced many 20th-century
composers. Among his best-known works are his
<span lang="fr">Pavane, Requiem, Sicilienne,</span>
nocturnes for piano and the songs
<span lang="fr">"Après un rêve"</span> and
<span lang="fr">"Clair de lune"</span>. Although his
best-known and most accessible compositions are
generally his earlier ones,
<span lang="fr">Fauré</span> composed many of his
most highly regarded works in his later years, in a
more harmonically and melodically complex style.
</p>
</div>
</div>
</div>
Custom Tablist (second demo)
About the second demo This demo has a large number of tabs in order to force scrolling, as well as a footer.
-
In this demo the tabset gains its accessible name from an
aria-labelset on the componentdiv -
The scroll buttons, which do appear in this example,
are
aria-describedbytheIDof the componentdiv -
The scroll buttons change state depending on the extent of scroll in
either direction. When changes occur there are multiple affordances
(mouse, keyboard, screen reader), particularly when a button becomes
aria-disabled - Footer content height subtracts from whatever explicit height is assigned the tabset.
Georges Auric (15 February 1899 – 23 July 1983) was a French composer, born in Lodève, Hérault, France. He was considered one of Les Six—The Group of Six—a group of artists informally associated with Jean Cocteau and Erik Satie. Before he turned 20 he had orchestrated and written incidental music for several ballets and stage productions. He also had a long and distinguished career as a film composer.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In sit amet massa auctor quam viverra malesuada. Maecenas eu lorem a ex ullamcorper rhoncus non vitae eros. Morbi tincidunt egestas lacus, eget consectetur nibh vestibulum aliquam. Nulla erat quam, hendrerit id congue suscipit, luctus ultricies urna. Nullam erat nisl, posuere id blandit non, porta eget justo. Integer faucibus sem ac maximus auctor. Aliquam et orci tempus, volutpat nisl sed, rhoncus eros. Praesent egestas felis risus, id feugiat purus ullamcorper a. Nunc malesuada, erat sit amet interdum fringilla, magna est iaculis diam, vitae vehicula mi elit eu erat. Praesent congue tortor ultrices, sagittis risus eget, suscipit orci. Vivamus eu vestibulum mauris. Suspendisse vel diam mauris. Sed ante enim, eleifend vel quam in, dignissim porttitor ipsum. Nunc suscipit felis nec elit blandit sollicitudin.
Vivamus ac porttitor risus. Nulla convallis, libero at consectetur viverra, nulla dolor tempus ipsum, quis iaculis orci lacus quis ex. Fusce ac turpis vehicula, efficitur quam sit amet, tristique lectus. Duis quis semper lectus. Vestibulum semper ligula et congue vestibulum. Quisque laoreet lacinia sapien ut faucibus. Suspendisse id molestie lectus. Etiam faucibus nec lacus sit amet egestas. Mauris quis congue mi, posuere pellentesque dolor. Mauris eget sodales nibh. Vestibulum ultrices quam id finibus euismod. Curabitur eleifend lorem non fringilla feugiat.
Maecenas efficitur et lorem sit amet bibendum. Sed a molestie odio, nec iaculis velit. Duis ut porta quam. Etiam aliquam fermentum erat, sed consequat neque viverra quis. Etiam vitae ante consequat, pretium nulla et, tempus risus. Cras eleifend ex mauris, sit amet faucibus velit fermentum vel. Integer malesuada, sapien vitae pellentesque lobortis, erat ligula viverra tellus, quis scelerisque nunc risus nec arcu. Quisque tincidunt tempor risus ac pulvinar. Aenean efficitur massa eu leo iaculis sagittis in sit amet velit. Sed egestas enim efficitur, facilisis tortor varius, fringilla tellus. Morbi pellentesque eleifend nulla, in malesuada sapien molestie id. Cras pharetra erat lectus, at mattis arcu imperdiet eget.
Aliquam ullamcorper mauris ut scelerisque ultrices. Maecenas dapibus, elit vitae interdum finibus, ligula velit interdum enim, id iaculis quam tortor non justo. In dapibus elit sed dolor tempus tempus. Quisque nunc nisi, suscipit a tellus a, accumsan varius arcu. Morbi interdum erat non auctor tempus. Praesent viverra dolor vel rutrum semper. Suspendisse iaculis massa sit amet mauris commodo faucibus. Etiam tempor velit dolor, vitae lobortis sem lacinia at. Nam viverra sapien eget mi suscipit tincidunt sed semper sapien. Maecenas ut turpis eu ligula ultrices dapibus. Nullam facilisis ipsum vitae rutrum laoreet. Donec euismod pretium tempor. Nullam velit ex, ullamcorper in consectetur ut, accumsan ac nulla. Suspendisse sem velit, elementum vitae leo et, suscipit volutpat urna.
Proin mattis eros vel nulla dapibus, id placerat tortor convallis. In a velit vel ex vestibulum egestas quis sed massa. Vestibulum eu nibh vel ex bibendum consectetur. Quisque sed purus ut mauris gravida bibendum. Ut dui nibh, volutpat nec tincidunt sed, laoreet vel purus. Vestibulum varius purus in justo laoreet, eu scelerisque tortor mollis. Proin efficitur ullamcorper magna, at finibus nisl fringilla id. Vivamus viverra vulputate quam sed aliquam. Nullam massa quam, viverra eget dictum vel, cursus vitae libero. Morbi lacinia, nisi quis blandit tristique, urna ex volutpat lectus, eget rutrum libero dolor ut arcu. Cras porta purus ac convallis mattis.
Claude Debussy (22 August 1862 – 25 March 1918) was a French composer. He is sometimes seen as the first Impressionist composer, although he vigorously rejected the term. He was among the most influential composers of the late 19th and early 20th centuries.
Gabriel Fauré (12 May 1845 – 4 November 1924) was a French composer, organist, pianist and teacher. He was one of the foremost French composers of his generation, and his musical style influenced many 20th-century composers. Among his best-known works are his Pavane, Requiem, Sicilienne, nocturnes for piano and the songs "Après un rêve" and "Clair de lune". Although his best-known and most accessible compositions are generally his earlier ones, Fauré composed many of his most highly regarded works in his later years, in a more harmonically and melodically complex style.
Jean Françaix (23 May 1912 – 25 September 1997) was a French neoclassical composer, pianist, and orchestrator known for his prolific output and vibrant style. Françaix composed for various genres, and is particularly known for his chamber works for piano as well as winds.
André Jolivet (8 August 1905 – 20 December 1974) was a French composer. Known for his devotion to French culture and musical thought, Jolivet drew on his interest in acoustics and atonality, as well as both ancient and modern musical influences, particularly on instruments used in ancient times. He composed in a wide variety of forms for many different types of ensembles.
Charles Koechlin (27 November 1867 – 31 December 1950), commonly known as Charles Koechlin, was a French composer, teacher and musicologist. Among his better known works is Les Heures persanes, a set of piano pieces based on the novel Vers Ispahan by Pierre Loti and The Seven Stars Symphony, a 7 movement symphony where each movement is themed around a different film star (all Silent era stars) who were popular at the time of the piece's writing (1933).
He was a political radical all his life and a passionate enthusiast for such diverse things as medieval music, The Jungle Book of Rudyard Kipling, Johann Sebastian Bach, film stars (especially Lilian Harvey and Ginger Rogers), traveling, stereoscopic photography and socialism. He once said: "The artist needs an ivory tower, not as an escape from the world, but as a place where he can view the world and be himself. This tower is for the artist like a lighthouse shining out across the world."
Darius Milhaud (4 September 1892 – 22 June 1974) was a French composer, conductor, and teacher. He was a member of Les Six—The Group of Six—and one of the most prolific composers of the 20th century. His compositions are influenced by jazz and Brazilian music and make extensive use of polytonality. Milhaud is considered one of the key modernist composers. He taught many future jazz and classical composers, including Burt Bacharach, Dave Brubeck, Philip Glass, Steve Reich, György Kurtág, Karlheinz Stockhausen and Iannis Xenakis among others.
Francis Poulenc (7 January 1899 – 30 January 1963) was a French composer and pianist. His compositions include songs, solo piano works, chamber music, choral pieces, operas, ballets, and orchestral concert music. Among the best-known are the piano suite Trois mouvements perpétuels (1919), the ballet Les biches (1923), the Concert champêtre (1928) for harpsichord and orchestra, the Organ Concerto (1938), the opera Dialogues des Carmélites (1957), and the Gloria (1959) for soprano, choir, and orchestra.
Erik Alfred Leslie Satie (17 May 1866 – 1 July 1925), better known as Erik Satie, was a French composer and pianist. The son of a French father and a British mother, he studied at the Paris Conservatoire but was undistinguished and did not obtain a diploma. In the 1880s he worked as a pianist in café-cabarets in Montmartre, Paris, and began composing works, mostly for solo piano, such as his Gymnopédies and Gnossiennes. He also wrote music for a Rosicrucian sect to which he was briefly attached.
Henri Sauguet (18 May 1901 – 22 June 1989) was a French composer. Born in Bordeaux, he adopted his mother's maiden name as part of his professional pseudonym. His output includes operas, ballets, four symphonies (1945, 1949, 1955, 1971), concertos, chamber and choral music and numerous songs, as well as film music. Although he experimented with musique concrète and expanded tonality, he remained opposed to particular systems and his music evolved little: he developed tonal or modal ideas in smooth curves, producing an art of clarity, simplicity and restraint.
Footer
When a Tablist is assigned a height value, if a footer is present as a direct child of the tablist,
the footer will steal height from the tabpanel.
<style>
.tab-custom-2 {
height: 420px;
margin-block: 1rem;
}
</style>
<div
aria-label="A partial list of French composers active in the 20th century"
class="nysa11y tablist tab-custom-2"
data-component="tablist"
data-html="custom"
role="tablist"
id="TabTwo">
<div data-part="tabs">
<div data-part="scrollButtons">
<button aria-describedby="TabTwo" data-scroll="to-start" type="button">
<span class="sr-only">visual scroll toward start</span>
</button>
<button aria-describedby="TabTwo" data-scroll="to-end" type="button">
<span class="sr-only">visual scroll toward end</span>
</button>
</div>
<div data-part="tabsEnclosure">
<!-- ==================================== -->
<i class="tabs__scroll-affordance-start"></i>
<!-- ==================================== -->
<div data-part="scrollContainer">
<!-- ======================== -->
<s data-part="sentinelStart"></s>
<!-- ======================== -->
<!-- //////// Tab state and associations.
| ---------------------------------------
| role="tab" REQUIRED: hardcode
| aria-controls="" Managed by JavaScript
| aria-selected="" Managed by JavaScript
| id="" Managed by JavaScript
| tabindex="" Managed by JavaScript
| type="button" Recommended: hardcode
| ---------------------------------------
| Inspect with DevTools. \\\\\\\\\\\\ -->
<button
role="tab"
aria-controls=""
aria-selected=""
id=""
tabindex=""
type="button"
lang="fr">Georges Auric</button>
<button
role="tab"
aria-controls=""
aria-selected=""
id=""
tabindex=""
type="button"
lang="fr">Claude Debussy</button>
<button
role="tab"
aria-controls=""
aria-selected=""
id=""
tabindex=""
type="button"
lang="fr">Gabriel Fauré</button>
<button
role="tab"
aria-controls=""
aria-selected=""
id=""
tabindex=""
type="button"
lang="fr">Jean Françaix</button>
<button
role="tab"
aria-controls=""
aria-selected=""
id=""
tabindex=""
type="button"
lang="fr">André Jolivet</button>
<button
role="tab"
aria-controls=""
aria-selected=""
id=""
tabindex=""
type="button"
lang="fr">Charles Koechlin</button>
<button
role="tab"
aria-controls=""
aria-selected=""
id=""
tabindex=""
type="button"
lang="fr">Darius Milhaud</button>
<button
role="tab"
aria-controls=""
aria-selected=""
id=""
tabindex=""
type="button"
lang="fr">Francis Poulenc</button>
<button
role="tab"
aria-controls=""
aria-selected=""
id=""
tabindex=""
type="button"
lang="fr">Erik Satie</button>
<button
role="tab"
aria-controls=""
aria-selected=""
id=""
tabindex=""
type="button"
lang="fr">Henri Sauguet</button>
<!-- ====================== -->
<s data-part="sentinelEnd"></s>
<!-- ====================== -->
</div>
<!-- ================================== -->
<i class="tabs__scroll-affordance-end"></i>
<!-- ================================== -->
</div>
</div>
<div data-part="tabpanels" tabindex="0">
<!-- ///// Tabpanel state and associations.
| -----------------------------------------
| role="tabpanel" REQUIRED: hardcode
| aria-labelledby="" Managed by JavaScript
| id="" Managed by JavaScript
| hidden Managed by JavaScript
| -----------------------------------------
| Inspect with DevTools. \\\\\\\\\\\\\\ -->
<div
role="tabpanel"
aria-labelledby=""
id=""
>
<p>
<a
href="https://en.wikipedia.org/wiki/Georges_Auric"
lang="fr">Georges Auric</a>
(15 February 1899 – 23 July 1983) was a French
composer, born in
<span lang="fr">Lodève, Hérault,</span> France. He
was considered one of
<span lang="fr">Les Six</span>—The Group of Six—a
group of artists informally associated with
<span lang="fr">Jean Cocteau</span> and
<span lang="fr">Erik Satie</span>. Before he turned
20 he had orchestrated and written incidental music
for several ballets and stage productions. He also
had a long and distinguished career as a film
composer.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing
elit. In sit amet massa auctor quam viverra
malesuada. Maecenas eu lorem a ex ullamcorper
rhoncus non vitae eros. Morbi tincidunt egestas
lacus, eget consectetur nibh vestibulum aliquam.
Nulla erat quam, hendrerit id congue suscipit,
luctus ultricies urna. Nullam erat nisl, posuere id
blandit non, porta eget justo. Integer faucibus sem
ac maximus auctor. Aliquam et orci tempus, volutpat
nisl sed, rhoncus eros. Praesent egestas felis
risus, id feugiat purus ullamcorper a. Nunc
malesuada, erat sit amet interdum fringilla, magna
est iaculis diam, vitae vehicula mi elit eu erat.
Praesent congue tortor ultrices, sagittis risus
eget, suscipit orci. Vivamus eu vestibulum mauris.
Suspendisse vel diam mauris. Sed ante enim, eleifend
vel quam in, dignissim porttitor ipsum. Nunc
suscipit felis nec elit blandit sollicitudin.
</p>
<p>
Vivamus ac porttitor risus. Nulla convallis, libero
at consectetur viverra, nulla dolor tempus ipsum,
quis iaculis orci lacus quis ex. Fusce ac turpis
vehicula, efficitur quam sit amet, tristique lectus.
Duis quis semper lectus. Vestibulum semper ligula et
congue vestibulum. Quisque laoreet lacinia sapien ut
faucibus. Suspendisse id molestie lectus. Etiam
faucibus nec lacus sit amet egestas. Mauris quis
congue mi, posuere pellentesque dolor. Mauris eget
sodales nibh. Vestibulum ultrices quam id finibus
euismod. Curabitur eleifend lorem non fringilla
feugiat.
</p>
<p>
Maecenas efficitur et lorem sit amet bibendum. Sed a
molestie odio, nec iaculis velit. Duis ut porta
quam. Etiam aliquam fermentum erat, sed consequat
neque viverra quis. Etiam vitae ante consequat,
pretium nulla et, tempus risus. Cras eleifend ex
mauris, sit amet faucibus velit fermentum vel.
Integer malesuada, sapien vitae pellentesque
lobortis, erat ligula viverra tellus, quis
scelerisque nunc risus nec arcu. Quisque tincidunt
tempor risus ac pulvinar. Aenean efficitur massa eu
leo iaculis sagittis in sit amet velit. Sed egestas
enim efficitur, facilisis tortor varius, fringilla
tellus. Morbi pellentesque eleifend nulla, in
malesuada sapien molestie id. Cras pharetra erat
lectus, at mattis arcu imperdiet eget.
</p>
<p>
Aliquam ullamcorper mauris ut scelerisque ultrices.
Maecenas dapibus, elit vitae interdum finibus,
ligula velit interdum enim, id iaculis quam tortor
non justo. In dapibus elit sed dolor tempus tempus.
Quisque nunc nisi, suscipit a tellus a, accumsan
varius arcu. Morbi interdum erat non auctor tempus.
Praesent viverra dolor vel rutrum semper.
Suspendisse iaculis massa sit amet mauris commodo
faucibus. Etiam tempor velit dolor, vitae lobortis
sem lacinia at. Nam viverra sapien eget mi suscipit
tincidunt sed semper sapien. Maecenas ut turpis eu
ligula ultrices dapibus. Nullam facilisis ipsum
vitae rutrum laoreet. Donec euismod pretium tempor.
Nullam velit ex, ullamcorper in consectetur ut,
accumsan ac nulla. Suspendisse sem velit, elementum
vitae leo et, suscipit volutpat urna.
</p>
<p>
Proin mattis eros vel nulla dapibus, id placerat
tortor convallis. In a velit vel ex vestibulum
egestas quis sed massa. Vestibulum eu nibh vel ex
bibendum consectetur. Quisque sed purus ut mauris
gravida bibendum. Ut dui nibh, volutpat nec
tincidunt sed, laoreet vel purus. Vestibulum varius
purus in justo laoreet, eu scelerisque tortor
mollis. Proin efficitur ullamcorper magna, at
finibus nisl fringilla id. Vivamus viverra vulputate
quam sed aliquam. Nullam massa quam, viverra eget
dictum vel, cursus vitae libero. Morbi lacinia, nisi
quis blandit tristique, urna ex volutpat lectus,
eget rutrum libero dolor ut arcu. Cras porta purus
ac convallis mattis.
</p>
</div>
<div
role="tabpanel"
aria-labelledby=""
id=""
hidden
>
<p>
<a
href="https://en.wikipedia.org/wiki/Claude_Debussy"
lang="fr">Claude Debussy</a>
(22 August 1862 – 25 March 1918) was a French
composer. He is sometimes seen as the first
Impressionist composer, although he vigorously
rejected the term. He was among the most influential
composers of the late 19th and early 20th centuries.
</p>
</div>
<div
role="tabpanel"
aria-labelledby=""
id=""
hidden
>
<p>
<a
href="https://en.wikipedia.org/wiki/Gabriel_Fauré"
lang="fr">Gabriel Fauré</a>
(12 May 1845 – 4 November 1924) was a French
composer, organist, pianist and teacher. He was one
of the foremost French composers of his generation,
and his musical style influenced many 20th-century
composers. Among his best-known works are his
<span lang="fr">Pavane, Requiem, Sicilienne,</span>
nocturnes for piano and the songs
<span lang="fr">"Après un rêve"</span> and
<span lang="fr">"Clair de lune"</span>. Although his
best-known and most accessible compositions are
generally his earlier ones,
<span lang="fr">Fauré</span> composed many of his
most highly regarded works in his later years, in a
more harmonically and melodically complex style.
</p>
</div>
<div
role="tabpanel"
aria-labelledby=""
id=""
hidden
>
<p>
<a
href="https://en.wikipedia.org/wiki/Jean_Françaix"
lang="fr">Jean Françaix</a>
(23 May 1912 – 25 September 1997) was a French
neoclassical composer, pianist, and orchestrator
known for his prolific output and vibrant style.
<span lang="fr">Françaix</span> composed for various
genres, and is particularly known for his chamber
works for piano as well as winds.
</p>
</div>
<div
role="tabpanel"
aria-labelledby=""
id=""
hidden
>
<p>
<a
href="https://en.wikipedia.org/wiki/André_Jolivet"
lang="fr">André Jolivet</a>
(8 August 1905 – 20 December 1974) was a French
composer. Known for his devotion to French culture
and musical thought,
<span lang="fr">Jolivet</span> drew on his interest
in acoustics and atonality, as well as both ancient
and modern musical influences, particularly on
instruments used in ancient times. He composed in a
wide variety of forms for many different types of
ensembles.
</p>
</div>
<div
role="tabpanel"
aria-labelledby=""
id=""
hidden
>
<p>
<a
href="https://en.wikipedia.org/wiki/Charles_Koechlin"
lang="fr">Charles Koechlin</a>
(27 November 1867 – 31 December 1950), commonly
known as <span lang="fr">Charles Koechlin</span>,
was a French composer, teacher and musicologist.
Among his better known works is
<span lang="fr">Les Heures persanes</span>, a set of
piano pieces based on the novel
<span lang="fr">Vers Ispahan</span> by
<span lang="fr">Pierre Loti</span> and The Seven
Stars Symphony, a 7 movement symphony where each
movement is themed around a different film star (all
Silent era stars) who were popular at the time of
the piece's writing (1933).
</p>
<p>
He was a political radical all his life and a
passionate enthusiast for such diverse things as
medieval music, The Jungle Book of Rudyard Kipling,
<span lang="de">Johann Sebastian Bach</span>, film
stars (especially Lilian Harvey and Ginger Rogers),
traveling, stereoscopic photography and socialism.
He once said: "The artist needs an ivory tower, not
as an escape from the world, but as a place where he
can view the world and be himself. This tower is for
the artist like a lighthouse shining out across the
world."
</p>
</div>
<div
role="tabpanel"
aria-labelledby=""
id=""
hidden
>
<p>
<a
href="https://en.wikipedia.org/wiki/Darius_Milhaud"
lang="fr">Darius Milhaud</a>
(4 September 1892 – 22 June 1974) was a French
composer, conductor, and teacher. He was a member of
<span lang="fr">Les Six</span>—The Group of Six—and
one of the most prolific composers of the 20th
century. His compositions are influenced by jazz and
Brazilian music and make extensive use of
polytonality. Milhaud is considered one of the key
modernist composers. He taught many future jazz and
classical composers, including Burt Bacharach, Dave
Brubeck, Philip Glass, Steve Reich,
<span lang="hu">György Kurtág</span>,
<span lang="de">Karlheinz Stockhausen</span> and
<span lang="el">Iannis Xenakis</span> among others.
</p>
</div>
<div
role="tabpanel"
aria-labelledby=""
id=""
hidden
>
<p>
<a
href="https://en.wikipedia.org/wiki/Francis_Poulenc"
lang="fr">Francis Poulenc</a>
(7 January 1899 – 30 January 1963) was a French
composer and pianist. His compositions include
songs, solo piano works, chamber music, choral
pieces, operas, ballets, and orchestral concert
music. Among the best-known are the piano suite
<span lang="fr">Trois mouvements perpétuels</span>
(1919), the ballet
<span lang="fr">Les biches</span> (1923), the
<span lang="fr">Concert champêtre</span> (1928) for
harpsichord and orchestra, the Organ Concerto
(1938), the opera
<span lang="fr">Dialogues des Carmélites</span>
(1957), and the Gloria (1959) for soprano, choir,
and orchestra.
</p>
</div>
<div
role="tabpanel"
aria-labelledby=""
id=""
hidden
>
<p>
<a
href="https://en.wikipedia.org/wiki/Erik Satie"
lang="fr">Erik Alfred Leslie Satie</a>
(17 May 1866 – 1 July 1925), better known as
<span lang="fr">Erik Satie</span>, was a French
composer and pianist. The son of a French father and
a British mother, he studied at the Paris
Conservatoire but was undistinguished and did not
obtain a diploma. In the 1880s he worked as a
pianist in café-cabarets in
<span lang="fr">Montmartre</span>, Paris, and began
composing works, mostly for solo piano, such as his
<span lang="fr">Gymnopédies</span> and
<span lang="fr">Gnossiennes</span>. He also wrote
music for a Rosicrucian sect to which he was briefly
attached.
</p>
</div>
<div
role="tabpanel"
aria-labelledby=""
id=""
hidden
>
<p>
<a
href="https://en.wikipedia.org/wiki/Henri_Sauguet"
lang="fr">Henri Sauguet</a>
(18 May 1901 – 22 June 1989) was a French composer.
Born in <span lang="fr">Bordeaux</span>, he adopted
his mother's maiden name as part of his professional
pseudonym. His output includes operas, ballets, four
symphonies (1945, 1949, 1955, 1971), concertos,
chamber and choral music and numerous songs, as well
as film music. Although he experimented with
<span lang="fr">musique concrète</span> and expanded
tonality, he remained opposed to particular systems
and his music evolved little: he developed tonal or
modal ideas in smooth curves, producing an art of
clarity, simplicity and restraint.
</p>
</div>
</div>
<div data-part="tabfooter">
<h3>Footer</h3>
<p>
When a Tablist is assigned a height value, if a footer is present as a direct child of the tablist,
the footer will steal height from the tabpanel.<br>
</p>
</div>
</div>
/**
* NYSA11y Tablist
* Path: /assets/nysa11y/tablist-custom.css
* Depends on /assets/nysa11y/tablist-custom.js
*/
@layer nysa11y {
body:has(.nysa11y) {
div.nysa11y.tablist[data-component="tablist"][data-html="custom"] {
--nysa11y-divider-thickness: 3px;
*,
*:before,
*:after {
box-sizing: border-box;
}
font-family:
"Proxima Nova",
-apple-system,
"BlinkMacSystemFont",
"Segoe UI",
"Roboto",
"Helvetica",
"Arial",
sans-serif;
display: flex;
flex-direction: column;
& [data-part="tabs"] {
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 3 3' width='3' height='3' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0h3v3H0z' fill='%23ededed'/%3E%3C/svg%3E%0A");
background-position: bottom;
background-repeat: repeat-x;
display: flex;
& [data-part="scrollButtons"] {
& button[data-scroll] {
background-color: var(
--nys-color-theme-weaker,
#eff6fb
);
border-color: var(--nys-color-theme-weak, #cddde9);
background-position: center;
background-repeat: no-repeat;
border-radius: 0;
height: 100%;
min-width: 44px;
border-inline: none;
border-block-start: none;
border-block-end-width: 3px;
border-start-end-radius: var(--nys-radius-md, 4px);
border-start-start-radius: var(--nys-radius-md, 4px);
border-end-start-radius: 0;
border-end-end-radius: 0;
margin-inline-end: 1px;
&:focus-visible {
outline: solid var(--nys-border-width-md, 2px)
var(--nys-color-focus, #004dd1);
outline-offset: calc(
var(--nys-space-2px, 2px) * -1
);
}
&[data-scroll="to-start"] {
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' width='24' height='24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpolyline fill='%23154973' points='14.724 12.486, 7.375 19.835, 7.013 20.710, 7.400 21.585, 8.275 21.960, 9.150 21.585, 16.849 13.911, 17.298 13.236, 17.448 12.486, 17.298 11.737, 16.849 11.062, 9.150 3.363, 8.262 3.000, 7.375 3.388, 7.000 4.263, 7.375 5.138, 14.724 12.486'/%3E%3C/svg%3E%0A");
background-size: contain;
transform: scaleX(-1);
&[aria-disabled="true"] {
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' width='24' height='24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpolyline fill='gray' points='14.724 12.486, 7.375 19.835, 7.013 20.710, 7.400 21.585, 8.275 21.960, 9.150 21.585, 16.849 13.911, 17.298 13.236, 17.448 12.486, 17.298 11.737, 16.849 11.062, 9.150 3.363, 8.262 3.000, 7.375 3.388, 7.000 4.263, 7.375 5.138, 14.724 12.486'/%3E%3C/svg%3E%0A");
}
}
&[data-scroll="to-end"] {
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' width='24' height='24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpolyline fill='%23154973' points='14.724 12.486, 7.375 19.835, 7.013 20.710, 7.400 21.585, 8.275 21.960, 9.150 21.585, 16.849 13.911, 17.298 13.236, 17.448 12.486, 17.298 11.737, 16.849 11.062, 9.150 3.363, 8.262 3.000, 7.375 3.388, 7.000 4.263, 7.375 5.138, 14.724 12.486'/%3E%3C/svg%3E%0A");
background-size: contain;
&[aria-disabled="true"] {
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' width='24' height='24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpolyline fill='gray' points='14.724 12.486, 7.375 19.835, 7.013 20.710, 7.400 21.585, 8.275 21.960, 9.150 21.585, 16.849 13.911, 17.298 13.236, 17.448 12.486, 17.298 11.737, 16.849 11.062, 9.150 3.363, 8.262 3.000, 7.375 3.388, 7.000 4.263, 7.375 5.138, 14.724 12.486'/%3E%3C/svg%3E%0A");
}
}
&[aria-disabled="true"] {
background-color: var(
--nys-color-neutral-10,
#f6f6f6
);
border-color: transparent;
pointer-events: none;
&:focus-visible {
outline: dashed var(--nys-border-width-md, 2px)
var(--nys-color-neutral-100, #d0d0ce);
}
}
}
}
& [data-part="tabsEnclosure"] {
position: relative;
overflow: hidden;
display: flex;
& .tabs__scroll-affordance-start,
& .tabs__scroll-affordance-end {
height: calc(100% - var(--nysa11y-divider-thickness));
pointer-events: none;
position: absolute;
width: var(--nys-space-200, 16px);
z-index: 10;
&[class$="-start"] {
background-image: linear-gradient(
to left,
transparent,
var(--nys-color-neutral-100, #d0d0ce)
);
left: 0px;
}
&[class$="-end"] {
background-image: linear-gradient(
to right,
transparent,
var(--nys-color-neutral-100, #d0d0ce)
);
right: 0px;
}
}
& [data-part="scrollContainer"] {
display: flex;
overflow-x: auto;
scroll-behavior: smooth;
scrollbar-width: none;
& [data-part^="sentinel"] {
height: 1px;
width: 1px;
flex-shrink: 0;
flex-grow: 0;
}
& button[role="tab"] {
background-color: var(--nys-color-surface, #ffffff);
border-color: var(--nys-color-neutral-50, #ededed);
border-start-end-radius: var(--nys-radius-md, 4px);
border-start-start-radius: var(
--nys-radius-md,
4px
);
border-style: none none solid;
border-width: var(--nysa11y-divider-thickness);
color: var(--nys-color-ink, #1b1b1b);
cursor: pointer;
display: grid;
font-family: var(
--nys-font-family-ui,
Proxima Nova,
-apple-system,
BlinkMacSystemFont,
Segoe UI,
Roboto,
Helvetica,
Arial,
sans-serif,
Apple Color Emoji,
Segoe UI Emoji,
Segoe UI Symbol
);
font-size: var(--nys-font-size-ui-md, 16px);
font-weight: var(--nys-font-weight-semibold, 600);
line-height: var(--nys-size-200, 16px);
margin-inline-end: 8px;
padding: var(--nys-space-200, 16px)
var(--nys-space-150, 12px);
place-content: center;
white-space: nowrap;
&:last-of-type {
margin-inline-end: 1px;
}
&:focus-visible {
outline: solid var(--nys-border-width-md, 2px)
var(--nys-color-focus, #004dd1);
outline-offset: calc(
var(--nys-space-2px, 2px) * -1
);
}
&:hover {
background-color: var(
--nys-color-theme-weaker,
#eff6fb
);
border-color: var(
--nys-color-theme-weak,
#cddde9
);
}
&[aria-selected="true"] {
background-color: var(
--nys-color-neutral-10,
#f6f6f6
);
border-color: var(--nys-color-theme, #154973);
&:hover {
background-color: var(
--nys-color-theme-weaker,
#eff6fb
);
border-color: var(
--nys-color-theme-strong,
#0e324f
);
}
}
}
}
}
}
& [data-part="tabpanels"] {
flex-grow: 1;
margin: 1rem;
overflow: auto;
overscroll-behavior: none;
padding: 1rem;
&:focus-visible {
outline: solid var(--nys-border-width-md, 2px)
var(--nys-color-focus, #004dd1);
}
& [role="tabpanel"] {
/* customize per content */
}
}
& [data-part="tabfooter"] {
/* customize per content */
}
}
/* Non-Tablist classes
Placed here, these take effect both inside and outside the Tablist */
a:link:focus-visible {
outline: solid var(--nys-border-width-md, 2px)
var(--nys-color-focus, #004dd1);
outline-offset: var(--nys-space-2px, 2px);
}
.sr-only {
border: 0 !important;
clip: rect(1px, 1px, 1px, 1px) !important;
-webkit-clip-path: inset(50%) !important;
clip-path: inset(50%) !important;
height: 1px !important;
overflow: hidden !important;
margin: -1px !important;
padding: 0 !important;
position: absolute !important;
width: 1px !important;
white-space: nowrap !important;
}
}
}
/*
* NYSA11y Tablist
* Path: /assets/nysa11y/tablist-custom.js
* Depends on /assets/nysa11y/tablist-custom.css
*/
const nysa11y = window.nysa11y || {};
class Tablist {
#selectorTablist = '[data-component="tablist"].nysa11y.tablist';
#selectorTab = '[role="tab"]';
#selectorPanel = '[role="tabpanel"]';
#selectorScrollButtons = '[data-part="scrollButtons"]';
#selectorScrollContainer = '[data-part="scrollContainer"]';
#selectorTabsEnclosure = '[data-part="tabsEnclosure"]';
#selectorSentinelStart = '[data-part="sentinelStart"]';
#selectorSentinelEnd = '[data-part="sentinelEnd"]';
#selectorScrollBtnStart = '[data-scroll="to-start"]';
#selectorScrollBtnEnd = '[data-scroll="to-end"]';
#selectorOverlayStart = ".tabs__scroll-affordance-start";
#selectorOverlayEnd = ".tabs__scroll-affordance-end";
#scrollStep = 300;
// Element-level expando used to disconnect a prior IntersectionObserver
// before wiring a new one when init() runs more than once.
#observerKey = "__nysa11yTablistObserver";
constructor(options = {}) {
this.container = options.container || document;
this.init();
}
init() {
const tablists = this.container.querySelectorAll(this.#selectorTablist);
if (!tablists.length) return;
tablists.forEach((tablistEl) => {
this.#ensureIds(tablistEl);
this.#setupTabs(tablistEl);
this.#setupScrollControls(tablistEl);
});
}
// Generate id / aria-controls / aria-labelledby only when missing, so
// hand-authored ids survive and ids stay unique across simultaneous tablists.
#ensureIds = (tablistEl) => {
const tabs = tablistEl.querySelectorAll(this.#selectorTab);
const panels = tablistEl.querySelectorAll(this.#selectorPanel);
tabs.forEach((tab, index) => {
const panel = panels[index];
const ariaControls = tab.getAttribute("aria-controls");
const linkedPanel = ariaControls
? tablistEl.querySelector(`#${CSS.escape(ariaControls)}`)
: null;
if (tab.id && ariaControls && linkedPanel) return;
const uid = crypto.randomUUID();
const tabId = `tab-${uid}`;
const panelId = `panel-${uid}`;
tab.id = tabId;
tab.setAttribute("aria-controls", panelId);
if (panel) {
panel.id = panelId;
panel.setAttribute("aria-labelledby", tabId);
}
});
};
#setupTabs = (tablistEl) => {
const tabs = tablistEl.querySelectorAll(this.#selectorTab);
if (!tabs.length) return;
let presetSelected = null;
tabs.forEach((tab) => {
tab.removeEventListener("click", this.#handleClick);
tab.addEventListener("click", this.#handleClick);
tab.removeEventListener("keydown", this.#handleKeydown);
tab.addEventListener("keydown", this.#handleKeydown);
if (!presetSelected && tab.getAttribute("aria-selected") === "true") {
presetSelected = tab;
}
});
this.#selectTab(tablistEl, presetSelected || tabs[0]);
};
#selectTab = (tablistEl, targetTab) => {
const tabs = tablistEl.querySelectorAll(this.#selectorTab);
tabs.forEach((tab) => {
const isSelected = tab === targetTab;
tab.setAttribute("aria-selected", isSelected ? "true" : "false");
if (isSelected) {
tab.removeAttribute("tabindex");
} else {
tab.tabIndex = -1;
}
const ariaControls = tab.getAttribute("aria-controls");
if (!ariaControls) return;
const panel = tablistEl.querySelector(`#${CSS.escape(ariaControls)}`);
if (!panel) return;
panel.hidden = !isSelected;
});
};
#handleClick = (event) => {
const tab = event.currentTarget;
const tablistEl = tab.closest(this.#selectorTablist);
if (!tablistEl) return;
this.#selectTab(tablistEl, tab);
tab.focus();
};
#handleKeydown = (event) => {
const tab = event.currentTarget;
const tablistEl = tab.closest(this.#selectorTablist);
if (!tablistEl) return;
const tabs = Array.from(tablistEl.querySelectorAll(this.#selectorTab));
const idx = tabs.indexOf(tab);
if (idx < 0) return;
let next = null;
switch (event.key) {
case "ArrowLeft":
next = tabs[(idx - 1 + tabs.length) % tabs.length];
break;
case "ArrowRight":
next = tabs[(idx + 1) % tabs.length];
break;
case "Home":
next = tabs[0];
break;
case "End":
next = tabs[tabs.length - 1];
break;
default:
return;
}
next.focus();
event.preventDefault();
event.stopPropagation();
};
#setupScrollControls = (tablistEl) => {
const scrollButtons = tablistEl.querySelector(this.#selectorScrollButtons);
const scrollContainer = tablistEl.querySelector(
this.#selectorScrollContainer,
);
const tabsEnclosure = tablistEl.querySelector(this.#selectorTabsEnclosure);
const sentinelStart = tablistEl.querySelector(this.#selectorSentinelStart);
const sentinelEnd = tablistEl.querySelector(this.#selectorSentinelEnd);
const scrollStartBtn = tablistEl.querySelector(
this.#selectorScrollBtnStart,
);
const scrollEndBtn = tablistEl.querySelector(this.#selectorScrollBtnEnd);
const overlayStart = tablistEl.querySelector(this.#selectorOverlayStart);
const overlayEnd = tablistEl.querySelector(this.#selectorOverlayEnd);
if (
!scrollButtons ||
!scrollContainer ||
!tabsEnclosure ||
!sentinelStart ||
!sentinelEnd
) {
return;
}
const states = { sentinelStart: true, sentinelEnd: true };
const prev = tablistEl[this.#observerKey];
if (prev && typeof prev.disconnect === "function") prev.disconnect();
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
const isVisible = entry.isIntersecting;
if (entry.target === sentinelStart) {
states.sentinelStart = isVisible;
if (overlayStart) {
overlayStart.style.display = isVisible ? "none" : "block";
}
if (scrollStartBtn) scrollStartBtn.ariaDisabled = isVisible;
}
if (entry.target === sentinelEnd) {
states.sentinelEnd = isVisible;
if (overlayEnd) {
overlayEnd.style.display = isVisible ? "none" : "block";
}
if (scrollEndBtn) scrollEndBtn.ariaDisabled = isVisible;
}
});
const hasOverflow = !states.sentinelStart || !states.sentinelEnd;
scrollButtons.style.display = hasOverflow ? "flex" : "none";
},
{ root: tabsEnclosure, threshold: 0.1 },
);
observer.observe(sentinelStart);
observer.observe(sentinelEnd);
tablistEl[this.#observerKey] = observer;
if (scrollStartBtn) {
scrollStartBtn.removeEventListener("click", this.#handleScrollClick);
scrollStartBtn.addEventListener("click", this.#handleScrollClick);
}
if (scrollEndBtn) {
scrollEndBtn.removeEventListener("click", this.#handleScrollClick);
scrollEndBtn.addEventListener("click", this.#handleScrollClick);
}
};
#handleScrollClick = (event) => {
const button = event.currentTarget;
const tablistEl = button.closest(this.#selectorTablist);
if (!tablistEl) return;
const scrollContainer = tablistEl.querySelector(
this.#selectorScrollContainer,
);
if (!scrollContainer) return;
const direction = button.dataset.scroll === "to-start" ? -1 : 1;
scrollContainer.scrollBy({
left: direction * this.#scrollStep,
behavior: "smooth",
});
};
}
nysa11y.Tablist = Tablist;
document.addEventListener("DOMContentLoaded", () => {
new nysa11y.Tablist();
});
About this pattern
A tablist
(ARIA role="tablist")
contains and associates a set of tab content selectors
(ARIA role="tab")
and tabpanel content items
(ARIA role="tabpanel")
with a display area. All tabs are present at all times.
Only one tabpanel may appear in the display area at a time; the others are hidden until invoked by activation of a tab.
Tablists are not used for navigation, though sometimes network activity may be needed to populate content.
Rather, they are used to "shuffle" or "swap" content chunks in the display area.
There is no native HTML tablist element; the name is taken from the ARIA role.
The display of a tabpanel is controlled by activation of the tab that labels the content. Tabs are button-like and option-like, and as a group they are list-like. Responsibilities of a tab include being able to take focus, to reflect selection state, and to be activated. Tabpanels may contain any valid HTML content. Tabs and tabpanels are typically closely co-located both visually and in code.
Success of the component depends primarily on effective interaction with a tab and the resulting changes in state to the tab and its paired tabpanel. At any given time only one of the set is presented. This state of being selected must be communicated visually, semantically, aurally, and programmatically with affordances:
- A selected tab is visually distinct
- When reached by a screen reader all tabs must announce their names, but when selected must also identify as such
- The tab must respond to its visible name when invoked by voice control systems
- While keyboard navigation between tabs occurs by Arrow, movement between tab and tabpanel occurs by Tab and Shift + Tab.
For assistive technologies most affordances depend on correct use of ARIA:
- If the tablist component has a visible label, such as an
h3element, associate them witharia-labelledby="ID". Otherwise, set anaria-label="descriptive string". - Ensure each tab
aria-controls="ID"its associated tabpanel. - Dynamically set the active tab to
aria-selected="true"and the others tofalse. - Each tabpanel must be
aria-labelledby="ID"its associated tab. - When the set of tabs is vertical in visual presentation, the parent tablist requires
aria-orientation="vertical".
Screen reader users benefit from tab announcements that include the total number of tabs in the parent tablist.
Screen reader and keyboard users benefit from placing the tabpanel perimeter in focus order with tabindex="0".
It is safer to require manual rather than automatic loading of tabpanel content.
This makes selection more explicitly determined by user choice and guards against performance problems with heavy tabpanel content.
The NYSDS Tab component implements all of the above.