アクセシビリティに配慮したアコーディオンをVueで作成する

2020/01/17

アクセシビリティの本を読んでいたので、復習もかねてVueでアコーディオンをつくってみます。

参考にした本
コーディングWebアクセシビリティ

まずはアコーディオンのコンポーネントをつくります。

AccordionListItem.vue

<template>
  <div>
    <h2>
      <button :aria-expanded="isShow ? 'true' : 'false'" :aria-controls="accordionName" @click="handleClick">
        <slot name="title"></slot>
      </button>
    </h2>
    <div :id="accordionName" :aria-hidden="isShow ? 'false': 'true'">
      <p>
        <slot name="body"></slot>
      </p>
    </div>
  </div>
</template>

<script>
  export default {
    name: "AccordionListItem",
    props: {
      accordionName: {
        type: String,
        required: true
      }
    },
    data() {
      return {
        isShow: false
      }
    },
    methods: {
      handleClick() {
        this.isShow = !this.isShow
      }
    }
  }
</script>

<style scoped>
  /*最低限のCSSのみ指定*/
  [aria-hidden] {
    display: none;
  }

  [aria-hidden="false"] {
    display: block;
  }

  [aria-expanded]::before {
    content: '\25ba\0020'
  }

  [aria-expanded="true"]::before {
    content: '\25bc\0020'
  }
</style>

ここで使用されているaria属性について

aria属性を指定することで支援技術のユーザー向けにHTMLの情報を追加することができる。

  • aria-expanded
    要素が畳まれている(false)か展開されている(true)かを指定します。
    畳まれてる、または展開されている要素自身につけるのではなく、それを制御している要素につけます。

  • aria-controls
    どの要素がどの要素から影響を受けるかを指定します。
    影響を与える側(ボタン側)にaria-controls、
    影響を受ける側にaria-controlsと同じidを指定することで関連付けをします。
    一意のものであればなんでも大丈夫です。

  • aria-hidden
    aria-hidden: trueを指定していると要素が支援技術から除外されます。
    aria-hiddenにCSSを指定することでaria-hiddenを切り替えると要素を表示、非表示にすることができます。

  [aria-hidden] {
    display: none;
  }

  [aria-hidden="false"] {
    display: block;
  }

親コンポーネント
AccordionList.vue

<template>
  <div>
    <AccordionListItem accordion-name="accordion1">
      <template v-slot:title>アコーディオン1</template>
      <template v-slot:body>アコーディオン1テキスト</template>
    </AccordionListItem>
    <AccordionListItem accordion-name="accordion2">
      <template v-slot:title>アコーディオン2</template>
      <template v-slot:body>アコーディオン2テキスト</template>
    </AccordionListItem>
  </div>
</template>


<script>

  import AccordionListItem from "./AccordionListItem";

  export default {
    name: "AccordionList",
    components: { AccordionListItem }
  }
</script>

実際に表示されるHTML

<div>
  <div>
    <h2>
      <button aria-controls="accordion1" aria-expanded="false">アコーディオン1</button>
    </h2>
    <div id="accordion1" aria-hidden="true">
      <p>アコーディオン1テキスト</p>
    </div>
  </div>
  <div>
    <h2>
      <button aria-controls="accordion2" aria-expanded="false">アコーディオン2</button>
    </h2>
    <div id="accordion2" aria-hidden="true">
      <p>アコーディオン2テキスト</p>
    </div>
  </div>
  </div>

アコーディオンのコンポーネントを使いまわせるように、タイトル、テキストをslotで親要素から指定できるようにします。
親要素からpropsでaccordionNameを受け取ってaria-controlsとidに指定します。
複数アコーディオンを設置する場合はaccordionNameが被らないようにする

タイトルをクリックしたときにmethodsでisShowステートを変更します。
isShowステートによってaria-expanded、aria-hiddenのtrue,falseを切り替えます。

isShowがtrue(表示されているとき)
aria-expanded="true"
aria-hidden="false"

isShowがfalse(表示されていないとき)
aria-expanded="false"
aria-hidden="true"

aria-hiddenとCSSのdisplayプロパティを紐付けることで表示、非表示を切り替える。
アコーディオンの中身が表示されていないときタイトルの横に右向き矢印、表示されているとき下向き矢印を表示するためにaria-expandedの値でCSSを変更する

  [aria-expanded]::before {
    content: '\25ba\0020'
  }

  [aria-expanded="true"]::before {
    content: '\25bc\0020'
  }

実際に作成したもの
(最低限のCSSのみ指定)