【React Native】Text#accessibilityLabelでよくあるエラーと解決策

2025-06-06

Text#accessibilityLabel は、React Native の Text コンポーネントに設定できる特別なプロパティ(props)の一つで、主にアクセシビリティを向上させるために使用されます。

アクセシビリティとは? アクセシビリティとは、障害を持つ人々(視覚障害、聴覚障害、運動障害など)も含む、より多くの人々がウェブサイトやアプリケーションを問題なく利用できるようにするための配慮や設計のことです。

accessibilityLabel の役割 視覚障害のあるユーザーは、スマートフォンの画面を読み上げる「スクリーンリーダー」という機能を利用してアプリを操作します。通常、スクリーンリーダーは画面に表示されているテキストの内容をそのまま読み上げます。

しかし、以下のようなケースでは、単に表示されているテキストを読み上げるだけでは、ユーザーにとって情報が分かりにくかったり、誤解を招いたりする可能性があります。

  1. アイコンに付随するテキスト
    例えば、ボタンに「→」と表示されているだけでは、それが「次へ」を意味するのか「進む」を意味するのかなど、具体的に何をするボタンなのかが分かりにくい場合があります。
  2. 略語や専門用語
    スクリーンリーダーが略語をそのまま読み上げてしまうと、意図しない発音になったり、意味が伝わりにくくなったりすることがあります。
  3. 情報が不足しているテキスト
    例えば、単に「OK」と表示されているだけでは、何がOKなのか、そのボタンを押すとどうなるのかが不明確な場合があります。

このような場合に accessibilityLabel を使用すると、スクリーンリーダーがテキストコンポーネントを読み上げる際に、実際に画面に表示されているテキストとは異なる、より具体的で分かりやすい説明を提供できます。

使用例

import React from 'react';
import { View, Text, StyleSheet } from 'react-native';

const App = () => {
  return (
    <View style={styles.container}>
      {/* 通常のテキスト */}
      <Text>登録</Text>

      {/* accessibilityLabel を使用した例 */}
      {/* 画面には「→」と表示されるが、スクリーンリーダーは「次のページに進む」と読み上げる */}
      <Text accessibilityLabel="次のページに進む" style={styles.iconText}></Text>

      {/* 短い略語に具体的な説明を追加する例 */}
      {/* 画面には「詳細」と表示されるが、スクリーンリーダーは「商品詳細ページへ」と読み上げる */}
      <Text accessibilityLabel="商品詳細ページへ" style={styles.buttonText}>
        詳細
      </Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  iconText: {
    fontSize: 30,
    marginTop: 20,
  },
  buttonText: {
    fontSize: 20,
    marginTop: 20,
    padding: 10,
    backgroundColor: '#eee',
  },
});

export default App;

上記の例では、

  • 「詳細」と表示されているボタンには accessibilityLabel="商品詳細ページへ" を設定し、より具体的な情報を提供しています。
  • Text コンポーネントに「→」と表示されている場合でも、accessibilityLabel="次のページに進む" を設定することで、スクリーンリーダーは「次のページに進む」と読み上げます。


accessibilityLabel が読み上げられない、または期待通りに機能しない

原因と対策

  • AndroidのTalkBack / iOSのVoiceOverの挙動の違い

    • スクリーンリーダーの種類(AndroidのTalkBack、iOSのVoiceOverなど)や、OSのバージョンによって、accessibilityLabel の読み上げ方や優先順位に微妙な違いが生じることがあります。
    • 例えば、Androidの一部のデバイスで、Text コンポーネントに accessibilityLabel を設定しても、子要素のテキストが読み上げられてしまうという報告もあります。これはスクリーンリーダー側のバグである可能性や、プラットフォームごとの実装の違いによるものです。
    • 対策
      実際に各プラットフォームのスクリーンリーダーをオンにしてテストを行うことが非常に重要です。開発者ツール(iOSのAccessibility Inspectorなど)も活用し、期待通りの読み上げが行われているか確認しましょう。
    • React Native の Text コンポーネントは、ネストされた Text の内容を結合して単一の文字列として扱います。このため、ネストされた TextaccessibilityLabel を設定しても、それが親の TextaccessibilityLabel によって上書きされたり、無視されたりすることがあります。
    • 対策
      accessibilityLabel は、スクリーンリーダーに読み上げさせたい情報の「全体」を表現する一番外側の Text(または View)に設定するのが基本です。特に、リンクを含むテキストなどでこの問題が起きやすいです。
      • リンクの場合は accessibilityRole="link" を設定し、onPress と組み合わせることを検討してください。
      • もしテキストを分割して読み上げさせたい場合は、それぞれの Text コンポーネントが独立したアクセシビリティ要素になるように構造を調整する必要があります(例: 各 TextView で囲み、それぞれに accessible={true} を設定するなど)。

大文字の乱用 (textTransform: 'uppercase')

原因と対策

  • 対策

    • accessibilityLabel を設定する際は、大文字・小文字を適切に含んだ、自然な文章で記述します。
    • デザイン上で大文字表示が必要な場合は、TextstyletextTransform: 'uppercase' を使用しつつ、accessibilityLabel には通常の文字列(Mixed Case or Sentence Case)を提供するようにします。
    // NG: スクリーンリーダーが「ピー・アール・オー・ダクト」と読み上げる可能性
    <Text style={{ textTransform: 'uppercase' }}>PRODUCT</Text>
    
    // OK: スクリーンリーダーは「製品」と読み上げる
    <Text accessibilityLabel="製品" style={{ textTransform: 'uppercase' }}>PRODUCT</Text>
    
  • 大文字のみのテキスト
    Text コンポーネントに textTransform: 'uppercase' を設定して表示を大文字にしている場合、スクリーンリーダーがそのテキストを略語(例: "USA" を「ユー・エス・エー」と読み上げるように)と誤認識し、一文字ずつ読み上げてしまうことがあります。これはユーザー体験を著しく損ねます。

不適切な情報の提供

原因と対策

  • 対策
    • accessibilityLabel は、その要素が「何であるか」と「何ができるか」を簡潔かつ明確に伝えるように記述します。
    • 「次へ」や「編集」など、具体的なアクションを促す言葉を含めると良いでしょう。
    • アイコンボタンの場合は、そのアイコンが視覚的に表す機能(例: 検索ボタンの虫眼鏡アイコンなら accessibilityLabel="検索")を明示的に記述します。
  • 不明瞭な情報
    短すぎたり、文脈を考慮しない accessibilityLabel は、ユーザーにとって意味不明な情報になる可能性があります。例えば、アイコンだけのボタンに「ボタン」とだけ設定しても、何をするボタンなのかが分かりません。
  • 冗長な情報
    accessibilityLabel が長すぎたり、すでにスクリーンリーダーが提供する情報(例: ボタンであれば「ボタン」という役割)を繰り返してしまったりすると、ユーザーは不必要に多くの情報を聞かされることになり、使い勝手が悪くなります。

テストとデバッグの困難さ

原因と対策

  • チーム内でのアクセシビリティ意識の共有

    • アクセシビリティは開発者だけでなく、デザイナーやプロダクトマネージャーも含めたチーム全体で意識すべきものです。デザイン段階からアクセシビリティを考慮することで、実装段階での手戻りを減らすことができます。
  • アクセシビリティツールの活用

    • iOS: Accessibility Inspector (Xcodeに付属): アプリのアクセシビリティツリーを視覚的に確認でき、各要素の accessibilityLabelaccessibilityRole などが正しく設定されているかを確認できます。
    • Android: Accessibility Scanner: アプリ画面をスキャンし、アクセシビリティに関する問題点(コントラスト比、タップターゲットのサイズ不足など)を自動的に検出してくれます。
    • これらのツールを積極的に利用し、問題の早期発見と修正に役立てましょう。
  • 実際のデバイスでのテスト不足
    シミュレータやエミュレータだけでなく、実際のデバイスで、各プラットフォームのスクリーンリーダー(iOSのVoiceOver、AndroidのTalkBack)を有効にしてテストすることが不可欠です。PC上の開発ツールだけでは、実際のユーザー体験を把握することはできません。



Text#accessibilityLabel は、主に視覚障害のあるユーザーがスクリーンリーダー(iOSのVoiceOverやAndroidのTalkBackなど)を使ってアプリを操作する際に、要素が何であるかをより分かりやすく伝えるためのプロパティです。

基本的な使い方:表示テキストと異なる情報を読み上げる

最も基本的な例として、画面に表示されているテキストと、スクリーンリーダーが読み上げるべきテキストが異なる場合に accessibilityLabel を使用します。

シナリオ
アイコンや略語など、視覚的に伝わる情報がスクリーンリーダーには分かりにくい場合。

import React from 'react';
import { View, Text, StyleSheet } from 'react-native';

const BasicExample = () => {
  return (
    <View style={styles.container}>
      {/* 例1: アイコンをテキストで表現し、補足情報を追加 */}
      {/* 画面表示: "次へ "
          スクリーンリーダー: "次のページに進む" */}
      <Text
        accessibilityLabel="次のページに進む"
        style={styles.text}
      >
        次へ 
      </Text>

      {/* 例2: 略語に正式名称を提供 */}
      {/* 画面表示: "詳細情報はこちら (FAQ)"
          スクリーンリーダー: "詳細情報はこちら よくある質問" */}
      <Text
        accessibilityLabel="詳細情報はこちら よくある質問"
        style={styles.text}
      >
        詳細情報はこちら (FAQ)
      </Text>

      {/* 例3: 数字や記号に説明を追加 */}
      {/* 画面表示: "¥1,500"
          スクリーンリーダー: "合計金額 1500円" */}
      <Text
        accessibilityLabel="合計金額 1500円"
        style={styles.text}
      >
        ¥1,500
      </Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
  },
  text: {
    fontSize: 20,
    marginVertical: 10,
    borderWidth: 1,
    borderColor: '#ccc',
    padding: 10,
  },
});

export default BasicExample;

解説

  • ユーザーは画面に表示されたテキストを読み取ることができなくても、accessibilityLabel によって提供される情報で内容を理解できます。
  • accessibilityLabel に設定された文字列が、スクリーンリーダーによって読み上げられます。
import React from 'react';
import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';

const GroupingExample = () => {
  return (
    <View style={styles.container}>
      {/* 例1: 価格と通貨単位をまとめる */}
      {/* 画面表示: "価格:¥ 500"
          スクリーンリーダー: "価格 500円" */}
      <View
        accessible={true} // このViewを単一のアクセシビリティ要素として認識させる
        accessibilityLabel="価格 500円"
        style={styles.itemContainer}
      >
        <Text style={styles.label}>価格:</Text>
        <Text style={styles.price}>¥</Text>
        <Text style={styles.price}>500</Text>
      </View>

      {/* 例2: 日付と曜日をまとめる */}
      {/* 画面表示: "2023年6月7日 (金)"
          スクリーンリーダー: "2023年6月7日 金曜日" */}
      <View
        accessible={true}
        accessibilityLabel="2023年6月7日 金曜日"
        style={styles.itemContainer}
      >
        <Text style={styles.date}>2023年6月7日</Text>
        <Text style={styles.dayOfWeek}>(金)</Text>
      </View>

      {/* 例3: タッチ可能な要素(ボタン)の例 */}
      {/* 画面表示: "購入" (アイコン付き)
          スクリーンリーダー: "商品を購入する ボタン" */}
      <TouchableOpacity
        accessible={true} // TouchableOpacityはデフォルトでaccessible={true}だが明示的に記載
        accessibilityLabel="商品を購入する" // 具体的な操作を伝える
        accessibilityRole="button" // 要素の役割を伝える
        style={styles.button}
        onPress={() => alert('商品を購入しました!')}
      >
        <Text style={styles.buttonText}>購入</Text>
        <Text style={styles.buttonIcon}></Text>
      </TouchableOpacity>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
  },
  itemContainer: {
    flexDirection: 'row',
    alignItems: 'center',
    marginVertical: 10,
    borderWidth: 1,
    borderColor: '#ddd',
    padding: 10,
  },
  label: {
    fontSize: 18,
    marginRight: 5,
  },
  price: {
    fontSize: 22,
    fontWeight: 'bold',
  },
  date: {
    fontSize: 18,
  },
  dayOfWeek: {
    fontSize: 16,
    marginLeft: 5,
    color: '#666',
  },
  button: {
    flexDirection: 'row',
    alignItems: 'center',
    backgroundColor: '#007bff',
    paddingVertical: 10,
    paddingHorizontal: 20,
    borderRadius: 5,
    marginTop: 20,
  },
  buttonText: {
    color: 'white',
    fontSize: 18,
    marginRight: 5,
  },
  buttonIcon: {
    fontSize: 20,
  },
});

export default GroupingExample;

解説

  • TouchableOpacity のようなインタラクティブなコンポーネントは、デフォルトで accessible={true} ですが、明示的に記述することも可能です。accessibilityRole="button" を設定することで、スクリーンリーダーはその要素がボタンであることをユーザーに伝えます。
  • グループ化された要素には、その View に設定された accessibilityLabel が読み上げられます。
  • Viewaccessible={true} を設定することで、その中の複数の Text コンポーネントが単一のアクセシビリティ要素としてグループ化されます。

大文字表示と accessibilityLabel の併用

CSSの textTransform: 'uppercase' を使ってテキストを大文字表示している場合、スクリーンリーダーがそれを略語と誤解して一文字ずつ読み上げてしまうことがあります。これを避けるために accessibilityLabel を使用します。

シナリオ
デザイン上、ボタンのテキストを全て大文字にしたいが、スクリーンリーダーには通常の読み方をしてほしい。

import React from 'react';
import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';

const UppercaseExample = () => {
  return (
    <View style={styles.container}>
      {/* NG例: accessibilityLabelがない場合、スクリーンリーダーが「ピー・アール・オー・ダクト」と読み上げる可能性 */}
      <Text style={styles.uppercaseText}>PRODUCT</Text>

      {/* OK例: accessibilityLabelを設定し、通常の読み方をさせる */}
      {/* 画面表示: "SUBMIT" (大文字)
          スクリーンリーダー: "送信" */}
      <TouchableOpacity
        accessible={true}
        accessibilityLabel="送信"
        accessibilityRole="button"
        style={styles.button}
        onPress={() => alert('送信ボタンが押されました')}
      >
        <Text style={styles.uppercaseButtonText}>SUBMIT</Text>
      </TouchableOpacity>

      {/* OK例: 略語だが、正式名称を読み上げさせたい場合 */}
      {/* 画面表示: "API" (大文字)
          スクリーンリーダー: "アプリケーション プログラミング インターフェース" */}
      <Text
        accessibilityLabel="アプリケーション プログラミング インターフェース"
        style={styles.uppercaseText}
      >
        API
      </Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
  },
  uppercaseText: {
    fontSize: 24,
    textTransform: 'uppercase', // 全て大文字で表示
    marginVertical: 10,
    borderWidth: 1,
    borderColor: '#ccc',
    padding: 10,
  },
  button: {
    backgroundColor: '#28a745',
    paddingVertical: 12,
    paddingHorizontal: 25,
    borderRadius: 8,
    marginTop: 20,
  },
  uppercaseButtonText: {
    color: 'white',
    fontSize: 20,
    fontWeight: 'bold',
    textTransform: 'uppercase', // 全て大文字で表示
  },
});

export default UppercaseExample;

解説

  • スクリーンリーダー向けには、accessibilityLabel で適切な、読み上げやすい文字列を提供することが重要です。
  • textTransform: 'uppercase' は表示上のスタイルのみを変更します。

これらの例は、React Native の Text#accessibilityLabel を効果的に使用して、アプリケーションのアクセシビリティを向上させる方法を示しています。

  • 大文字表示(textTransform: 'uppercase')を使用する場合は、スクリーンリーダー向けに適切な読み上げテキストを accessibilityLabel で提供します。
  • 複数の Text コンポーネントが論理的に一つの意味を持つ場合は、親の Viewaccessible={true}accessibilityLabel を設定してグループ化します。
  • accessibilityLabel は、表示されているテキストだけでは情報が不足する場合に、スクリーンリーダー向けに具体的な情報を提供するために使います。


Text#accessibilityLabel は特定のテキスト要素の読み上げ内容を直接指定するのに適していますが、React Native のアクセシビリティAPIには、より柔軟な表現やコンテキスト提供を可能にする他のプロパティやパターンが存在します。

accessibilityValue と accessibilityRole / accessibilityState との組み合わせ

accessibilityLabel が要素の「名前」や「説明」を提供するのに対し、accessibilityValue は要素の「現在の値」を、accessibilityRole は要素の「役割」(例: ボタン、スライダー)、accessibilityState は要素の「状態」(例: 選択されている、チェック済み)を提供します。これらを組み合わせることで、よりリッチなアクセシビリティ情報を提供できます。

シナリオ
スライダーの現在の値や、チェックボックスの状態を正確に伝えたい場合。

import React, { useState } from 'react';
import { View, Text, StyleSheet, Slider, Switch, TouchableOpacity } from 'react-native';

const AlternativeMethodsExample = () => {
  const [sliderValue, setSliderValue] = useState(50);
  const [isSwitchOn, setIsSwitchOn] = useState(false);

  return (
    <View style={styles.container}>
      {/* 例1: スライダーとその値 */}
      {/* accessibilityLabelは「音量」、accessibilityValueは現在の値 */}
      <Text style={styles.label}>音量:</Text>
      <Slider
        style={{ width: 200, height: 40 }}
        minimumValue={0}
        maximumValue={100}
        value={sliderValue}
        onValueChange={setSliderValue}
        step={1}
        accessible={true}
        accessibilityLabel="音量" // スライダーの目的
        accessibilityRole="adjustable" // 調整可能な要素
        // accessibilityValue には valuetext を指定
        accessibilityValue={{
          min: 0,
          max: 100,
          now: sliderValue,
          text: `${sliderValue}%` // スクリーンリーダーが読み上げる具体的な値
        }}
        accessibilityHint="音量を調整するには、左右にスワイプしてください。" // 操作ヒント
      />
      <Text>現在の音量: {sliderValue}%</Text>

      {/* 例2: スイッチとその状態 */}
      {/* accessibilityLabelは「通知」、accessibilityStateはon/offの状態 */}
      <View style={styles.row}>
        <Text style={styles.label}>通知をオンにする</Text>
        <Switch
          onValueChange={setIsSwitchOn}
          value={isSwitchOn}
          accessible={true}
          accessibilityLabel="通知" // スイッチの目的
          accessibilityRole="switch" // スイッチであること
          // accessibilityState には checked 状態を指定
          accessibilityState={{ checked: isSwitchOn }}
          accessibilityHint="通知のオン/オフを切り替えます"
        />
      </View>

      {/* 例3: 複数の情報をまとめて読み上げたいが、動的なテキストを含む場合 */}
      {/* accessibilityLabelの代わりに、コンテンツの自動読み上げと、accessibilityHintで補足 */}
      <TouchableOpacity
        style={styles.itemButton}
        onPress={() => alert('商品詳細へ移動')}
        accessible={true}
        accessibilityRole="button"
        // accessibilityLabel の代わりに、内部のTextコンポーネントが読み上げられる
        // ヒントで追加情報を提供する
        accessibilityHint="商品詳細を見るには、ダブルタップしてください。"
      >
        <Text style={styles.itemName}>コーヒー豆 (コロンビア)</Text>
        <Text style={styles.itemPrice}>¥1,200</Text>
      </TouchableOpacity>
      <Text style={styles.infoText}>上記ボタンは`accessibilityLabel`を使用せず、内部のテキストが読み上げられます。</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
  },
  label: {
    fontSize: 18,
    marginTop: 20,
    marginBottom: 5,
  },
  row: {
    flexDirection: 'row',
    alignItems: 'center',
    marginTop: 20,
  },
  itemButton: {
    backgroundColor: '#f0f0f0',
    padding: 15,
    borderRadius: 8,
    marginTop: 30,
    width: '80%',
    alignItems: 'center',
  },
  itemName: {
    fontSize: 20,
    fontWeight: 'bold',
  },
  itemPrice: {
    fontSize: 18,
    color: '#555',
    marginTop: 5,
  },
  infoText: {
    fontSize: 14,
    color: '#888',
    marginTop: 10,
    textAlign: 'center',
  },
});

export default AlternativeMethodsExample;

解説

  • TouchableOpacity の例 (動的なテキスト)
    • この例では、accessibilityLabel を明示的に設定していません。代わりに、TouchableOpacity 内の Text コンポーネント(商品名と価格)がそのまま連結して読み上げられます。
    • もし、連結されたテキストの読み上げ順序や内容が意図通りであれば、これで十分な場合があります。
    • accessibilityHint を使用して、追加の操作方法をユーザーに伝えることができます。
  • Switch の例
    • accessibilityRole="switch" でスイッチであることを明示します。
    • accessibilityState={{ checked: isSwitchOn }} で、スイッチがオンかオフかをスクリーンリーダーに伝えます。これにより「通知、オン、スイッチ」のように読み上げられます。
  • Slider の例
    • accessibilityLabel="音量" でスライダーの目的を伝えます。
    • accessibilityRole="adjustable" で、ユーザーが調整可能な要素であることを伝えます。
    • accessibilityValue には、min, max, now (現在の値), text (読み上げ文字列) を含めることで、スクリーンリーダーが「音量、現在の値50%、スライダー」のように読み上げます。
    • accessibilityHint で操作方法のヒントを提供できます。

accessibilityLiveRegion / aria-live (Webとの互換性を意識する場合)

これは Text コンポーネントに直接設定するものではありませんが、画面上のコンテンツが動的に変化した際に、その変化をスクリーンリーダーに自動的に読み上げさせたい場合に利用します。accessibilityLiveRegion はAndroidの機能に近く、iOSでは UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, '読み上げたいテキスト'); のようなネイティブAPIの直接利用や、より高度な手段が必要になることがあります。

シナリオ
フォーム送信後に「送信が完了しました!」というメッセージが表示された際に、ユーザーに自動的に読み上げさせたい。

import React, { useState } from 'react';
import { View, Text, StyleSheet, Button, ActivityIndicator } from 'react-native';

const LiveRegionExample = () => {
  const [message, setMessage] = useState('');
  const [loading, setLoading] = useState(false);

  const handleSubmit = () => {
    setLoading(true);
    setMessage(''); // 古いメッセージをクリア
    setTimeout(() => {
      setMessage('フォームの送信が完了しました!');
      setLoading(false);
    }, 2000);
  };

  return (
    <View style={styles.container}>
      <Button title="フォームを送信" onPress={handleSubmit} />
      {loading && <ActivityIndicator size="large" color="#0000ff" style={styles.indicator} />}

      {/* accessibilityLiveRegion を "polite" に設定することで、コンテンツの変化を自動的に読み上げる */}
      {/* 通常、重要なアラートには "assertive" を使用し、それほど緊急でないものには "polite" を使用します */}
      {message ? (
        <Text
          style={styles.messageText}
          // Androidの場合、このView内の変更を自動的に読み上げる
          // iOSでは、これだけでは自動読み上げされない場合があるため、ネイティブモジュールの利用を検討
          accessibilityLiveRegion="polite"
        >
          {message}
        </Text>
      ) : null}
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
  },
  indicator: {
    marginVertical: 20,
  },
  messageText: {
    fontSize: 18,
    fontWeight: 'bold',
    color: 'green',
    marginTop: 20,
  },
});

export default LiveRegionExample;

解説

  • 注意点として、iOSでは accessibilityLiveRegion が常に期待通りに機能するわけではありません。より確実な自動読み上げには、ネイティブモジュールを介して UIAccessibilityPostNotification を使用するなどの方法が検討されます。
  • "assertive" に設定すると、より緊急性の高い情報として即座に読み上げられます(例: エラーメッセージ)。
  • accessibilityLiveRegion="polite" を設定することで、その要素内のテキストコンテンツが変更された際に、スクリーンリーダーがユーザーの現在のタスクを妨げない程度に、その変更を読み上げます。

accessibilityLabel の動的な生成

accessibilityLabel は静的な文字列だけでなく、状態やデータに基づいて動的に生成することも可能です。

シナリオ
ユーザー名や未読メッセージ数など、表示内容が変化する要素に適切な読み上げを提供したい。

import React, { useState } from 'react';
import { View, Text, StyleSheet, Button } from 'react-native';

const DynamicLabelExample = () => {
  const [userName, setUserName] = useState('ゲスト');
  const [unreadCount, setUnreadCount] = useState(0);

  return (
    <View style={styles.container}>
      {/* 例1: ユーザー名が動的に変わる */}
      {/* 画面表示: "こんにちは、[ユーザー名]さん!"
          スクリーンリーダー: "こんにちは、[ユーザー名]さん" */}
      <Text
        accessibilityLabel={`こんにちは、${userName}さん`}
        style={styles.text}
      >
        こんにちは、{userName}さん!
      </Text>
      <Button title="ユーザー名を変更" onPress={() => setUserName('田中')} />

      {/* 例2: 未読メッセージ数に応じて読み上げを変える */}
      {/* 画面表示: "メッセージ ([未読数])"
          スクリーンリーダー: "未読メッセージ [未読数]件" または "未読メッセージはありません" */}
      <Text
        accessibilityLabel={
          unreadCount > 0
            ? `未読メッセージ ${unreadCount}件`
            : '未読メッセージはありません'
        }
        style={styles.text}
      >
        メッセージ ({unreadCount})
      </Text>
      <Button title="未読メッセージを追加" onPress={() => setUnreadCount(prev => prev + 1)} />
      <Button title="未読メッセージをクリア" onPress={() => setUnreadCount(0)} />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
  },
  text: {
    fontSize: 20,
    marginVertical: 10,
    borderWidth: 1,
    borderColor: '#ccc',
    padding: 10,
  },
});

export default DynamicLabelExample;

解説

  • 条件分岐(三項演算子など)を使って、状態に応じた異なる accessibilityLabel を提供することも可能です。これにより、スクリーンリーダーがより適切なコンテキストを読み上げることができます。
  • JavaScriptのテンプレートリテラル (``) を使用して、現在の状態変数を accessibilityLabel の文字列に組み込むことができます。

Text#accessibilityLabel はテキストの読み上げをコントロールするための基本ですが、より複雑なUIや動的なコンテンツに対しては、以下のプロパティやアプローチを組み合わせて使用することが重要です。

  • 動的な accessibilityLabel の生成: コンポーネントの状態やデータに応じて、読み上げテキストをリアルタイムで変更する。
  • accessibilityLiveRegion: 動的なコンテンツの変化をスクリーンリーダーに自動的に読み上げさせる(主にAndroid)。
  • accessible={true}View によるグループ化: 複数の要素を一つの論理的な塊としてスクリーンリーダーに認識させ、より簡潔な読み上げを可能にする。
  • accessibilityValue: スライダーやプログレスバーなど、値を持つ要素の現在の値と範囲を伝える。
  • accessibilityState: 要素の現在の状態(選択済み、有効/無効、チェック済みなど)を伝える。
  • accessibilityRole: 要素の役割(ボタン、リンク、スライダーなど)を定義し、スクリーンリーダーにそのインタラクションを伝える。