React Native Text#nativeID 徹底解説:アクセシビリティとiOS連携の鍵
nativeID
は、React Nativeのコンポーネント(特にView
やText
など)に付与できるプロパティの一つです。このプロパティの主な目的は、ネイティブコード(iOSのSwift/Objective-C、AndroidのJava/Kotlin)から特定のビュー要素を識別できるようにすることです。
React Nativeで開発するアプリは、最終的にネイティブのUIコンポーネントにレンダリングされます。通常、JavaScript側で要素を操作する際はReactのRefなどを使用しますが、より低レベルなネイティブの機能にアクセスしたり、ネイティブモジュールと連携したりする際に、JavaScript側で定義したUI要素をネイティブコードから参照したい場合があります。その際にnativeID
が役立ちます。
主な用途
-
アクセシビリティ (Accessibility): 特に重要なのがアクセシビリティです。例えば、スクリーンリーダー(視覚障害者向けの読み上げ機能)を使用する際に、ある
TextInput
に対して、そのラベルとなるText
コンポーネントを関連付けたい場合があります。nativeID
とaccessibilityLabelledBy
プロパティを組み合わせることで、この関連付けを行うことができます。例:
<View> <Text nativeID="formLabel">入力フィールドのラベル</Text> <TextInput accessibilityLabel="入力" accessibilityLabelledBy="formLabel" /> </View>
この例では、
TextInput
にフォーカスが当たった際に、スクリーンリーダーが「入力、編集ボックス、入力フィールドのラベル」のように読み上げることが期待されます。 -
InputAccessoryView との連携 (iOS): iOSでは、キーボードの上にカスタムツールバーを表示する
InputAccessoryView
というコンポーネントがあります。このInputAccessoryView
を特定のTextInput
に関連付けるためにnativeID
が使われます。const inputAccessoryViewID = 'uniqueID'; <ScrollView> <TextInput inputAccessoryViewID={inputAccessoryViewID} onChangeText={setText} value={text} placeholder={'ここに入力してください…'} /> </ScrollView> <InputAccessoryView nativeID={inputAccessoryViewID}> <Button onPress={() => setText('')} title="テキストをクリア" /> </InputAccessoryView>
ここでは、
TextInput
のinputAccessoryViewID
とInputAccessoryView
のnativeID
を同じ値にすることで、両者を紐付けています。 -
ネイティブコードからの要素特定: 非常に稀なケースですが、JavaScriptレイヤーで定義されたReact Nativeのビュー(例:
Text
)を、直接ネイティブコード側からIDを使って検索・操作したい場合に利用されることがあります。nativeID
を付与することで、ネイティブビューヒエラルキー内でその要素を一意に識別する手がかりとなります。
注意点
- デバッグ/テストIDとの違い:
testID
という似たようなプロパティがありますが、これは主に自動テストツール(例: Detox)から要素を特定するために使用されます。nativeID
はよりネイティブの連携やアクセシビリティの目的で使われます。 - ネイティブの実装:
nativeID
は、React Nativeが内部で各プラットフォームのネイティブビューにIDを割り当てるためのヒントとして使用されます。JavaScript側で単にIDを付与するだけでなく、そのIDがネイティブ側でどのように利用されるかを理解しておくことが重要です。 - 一意性:
nativeID
は、そのスクリーン(またはビューヒエラルキー)内で一意である必要があります。重複するIDを使用すると予期せぬ動作を引き起こす可能性があります。
nativeID の重複
エラーの症状
- デバッグ中に、ネイティブ側で要素を識別しようとした際に、期待する要素が見つからないか、複数の要素がヒットしてしまう。
InputAccessoryView
などが正しく表示されない、または複数のTextInput
で共有しようとした場合に問題が発生する。- アクセシビリティツール(VoiceOverやTalkBackなど)が正しく要素を読み上げない、または意図しない要素を読み上げる。
原因
- 同じ
nativeID
を複数のコンポーネントに割り当てている。nativeID
はその名の通り、ネイティブレイヤーでの一意な識別子として機能するため、重複は許容されません。特にリストレンダリングなどで動的にコンポーネントを生成する際に、ユニークなIDを生成し忘れることがあります。
トラブルシューティング
accessibilityLabelledBy
で使用する場合、参照先のnativeID
が本当にその画面内で一意であることを確認してください。- 動的に
nativeID
を生成する場合は、ループインデックスやユニークなキー(UUIDなど)を組み合わせて一意性を保証します。{items.map((item, index) => ( <Text key={item.id} nativeID={`itemLabel-<span class="math-inline">\{item\.id\}\-</span>{index}`}> {item.name} </Text> ))}
- コード全体を検索し、重複する
nativeID
がないか確認します。
アクセシビリティ関連の誤解や不適切な使用
エラーの症状
- ユーザーが期待する操作ができない(例: キーボードナビゲーションで特定の要素にフォーカスできない)。
accessibilityLabelledBy
が機能しない。- スクリーンリーダーが要素を読み飛ばす、または意味不明な読み上げをする。
原因
- 複雑なUIにおいて、アクセシビリティの論理的な流れが設計されていない。
nativeID
を付与しただけで、その要素がアクセシブルになるわけではないという誤解。nativeID
は設定しているが、accessibilityLabelledBy
などの関連プロパティが正しく設定されていない。
トラブルシューティング
- アクセシビリティテストツールの活用
iOSのVoiceOverやAndroidのTalkBackといったネイティブのアクセシビリティ機能を実際に使用して、アプリをテストすることが非常に重要です。シミュレーターやエミュレーターだけでなく、実際のデバイスでのテストも行いましょう。また、Accessibility Inspector
などのデバッグツールも役立ちます。 - 役割(accessibilityRole)の指定
要素の役割を明確にすることで、スクリーンリーダーがより適切な読み上げを行います。<Text nativeID="headerTitle" accessibilityRole="header"> セクションタイトル </Text>
- accessible プロパティの確認
特定のビューがスクリーンリーダーで読み上げられるようにしたい場合は、accessible={true}
を設定する必要がある場合があります。ただし、多くのCore Componentはデフォルトでアクセシブルです。 - accessibilityLabelledBy の正しい使用
accessibilityLabelledBy
を使用する際は、参照するnativeID
が正確に一致していることを確認します。// NG: nativeIDとaccessibilityLabelledByが一致しない // <Text nativeID="myLabel">ラベル</Text> // <TextInput accessibilityLabelledBy="labelForInput" /> // OK: nativeIDとaccessibilityLabelledByが一致する <Text nativeID="myLabel">ラベル</Text> <TextInput accessibilityLabelledBy="myLabel" />
InputAccessoryView との連携問題 (iOS)
エラーの症状
InputAccessoryView
が予期せず消える。- 複数の
TextInput
で同じInputAccessoryView
を共有しようとすると、一部のTextInput
でしか表示されない。 - キーボードの上にカスタムツールバーが表示されない。
原因
- React Nativeのバージョンによる問題。特定のバージョンで、複数の
TextInput
が同じinputAccessoryViewID
を共有する際にバグがある場合があります(GitHubのIssueなどで報告されていることがあります)。 InputAccessoryView
のnativeID
とTextInput
のinputAccessoryViewID
が一致していない。
- Modal との干渉
Modal
コンポーネントを使用している場合に、InputAccessoryView
が正しく表示されないことがあります。これは、Modal
が新しいネイティブウィンドウを作成するため、InputAccessoryView
がそのコンテキストを失うことがあるためです。Modal
のpresentationStyle
プロパティをoverFullScreen
に設定することで解決することがある、という報告があります。- Modal の表示/非表示に応じて、
InputAccessoryView
を再レンダリングするような状態管理を検討します。
- 複数 TextInput の共有
複数のTextInput
で同じInputAccessoryView
を使用する場合、特にReact Nativeの特定のバージョンで問題が発生することがあります。その場合は、以下の代替案を検討します。- 各 TextInput にユニークな InputAccessoryView を持たせる
コードの重複は増えますが、最も確実な方法です。 - 状態管理で表示を切り替える
InputAccessoryView
自体は常にレンダリングしておき、どのTextInput
がフォーカスされているかに応じて、InputAccessoryView
の中身や表示/非表示を制御するロジックを実装します。 - 最新のReact Nativeバージョンへのアップデート
既知のバグであれば、新しいバージョンで修正されている可能性があります。
- 各 TextInput にユニークな InputAccessoryView を持たせる
- IDの一致確認
InputAccessoryView
のnativeID
と、関連付けたいTextInput
のinputAccessoryViewID
が完全に一致していることを確認します。const accessoryId = 'myInputAccessory'; <InputAccessoryView nativeID={accessoryId}> {/* カスタムツールバーのコンポーネント */} </InputAccessoryView> <TextInput inputAccessoryViewID={accessoryId} />
- ネイティブデバッグツール
iOSの場合はXcodeのView Debugger、Androidの場合はAndroid StudioのLayout Inspectorを使用して、ネイティブビューのヒエラルキーを確認し、nativeID
がネイティブレイヤーでどのように認識されているかを直接調べることができます。 - React Native Debugger
React Native Debuggerを使ってコンポーネントツリーを確認し、nativeID
プロパティが正しく反映されているか視覚的に確認できます。 - コンソールログの活用
console.log()
を使って、nativeID
が期待通りに設定されているか、動的に生成されるIDがユニークであるかなどを確認します。
Text#nativeID
のプログラミング例
nativeID
は主に以下の2つの主要なユースケースで利用されます。
- アクセシビリティ (
accessibilityLabelledBy
との連携) - iOS の
InputAccessoryView
との連携
それぞれの例を見ていきましょう。
例1: アクセシビリティ (accessibilityLabelledBy
との連携)
この例では、Text
コンポーネントに nativeID
を付与し、それを TextInput
コンポーネントの accessibilityLabelledBy
プロパティで参照することで、スクリーンリーダー(視覚補助機能)が TextInput
の目的をより明確に読み上げるようにします。
import React, { useState } from 'react';
import { View, Text, TextInput, StyleSheet, Button, Alert } from 'react-native';
const AccessibilityExample = () => {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = () => {
Alert.alert('ログイン', `ユーザー名: ${username}\nパスワード: ${password}`);
};
return (
<View style={styles.container}>
{/* ユーザー名入力フィールドのセクション */}
<View style={styles.inputGroup}>
{/*
Text コンポーネントに nativeID を付与
このIDは、TextInputが何のための入力フィールドであるかをスクリーンリーダーに伝えるために使われます。
*/}
<Text nativeID="usernameLabel" style={styles.label}>
ユーザー名:
</Text>
<TextInput
style={styles.input}
value={username}
onChangeText={setUsername}
placeholder="ユーザー名を入力"
// accessibilityLabelledBy で Text の nativeID を参照
// これにより、スクリーンリーダーは「ユーザー名: テキストフィールド」のように読み上げます。
accessibilityLabelledBy="usernameLabel"
autoCapitalize="none"
/>
</View>
{/* パスワード入力フィールドのセクション */}
<View style={styles.inputGroup}>
<Text nativeID="passwordLabel" style={styles.label}>
パスワード:
</Text>
<TextInput
style={styles.input}
value={password}
onChangeText={setPassword}
placeholder="パスワードを入力"
secureTextEntry
// ここでも nativeID を参照
accessibilityLabelledBy="passwordLabel"
/>
</View>
<Button title="ログイン" onPress={handleSubmit} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
padding: 20,
backgroundColor: '#f5f5f5',
},
inputGroup: {
marginBottom: 20,
},
label: {
fontSize: 16,
fontWeight: 'bold',
marginBottom: 5,
},
input: {
height: 40,
borderColor: '#ccc',
borderWidth: 1,
borderRadius: 5,
paddingHorizontal: 10,
backgroundColor: '#fff',
},
});
export default AccessibilityExample;
このコードのポイント
- これにより、スクリーンリーダーを使用しているユーザーは、入力フィールドにフォーカスした際に「ユーザー名: テキストフィールド」や「パスワード: テキストフィールド」といった、より意味のあるコンテキスト情報を受け取ることができます。
- それぞれの
TextInput
は、accessibilityLabelledBy
プロパティで対応するText
のnativeID
を参照しています。 usernameLabel
とpasswordLabel
というユニークなnativeID
を持つText
コンポーネントがあります。
この例は iOSのみ で動作します。InputAccessoryView
は、キーボードの上に表示されるカスタムツールバーを提供します。これを特定の TextInput
に関連付けるために nativeID
を使用します。
import React, { useState } from 'react';
import {
View,
Text,
TextInput,
StyleSheet,
Button,
Platform,
InputAccessoryView, // iOS専用
ScrollView,
} from 'react-native';
const InputAccessoryExample = () => {
const [textInput1, setTextInput1] = useState('');
const [textInput2, setTextInput2] = useState('');
// InputAccessoryView の ID を定義
const accessoryViewID = 'myCustomKeyboardAccessory';
// 入力フィールドをクリアする関数
const clearInput = (setter) => {
setter('');
};
return (
<View style={styles.container}>
<ScrollView contentContainerStyle={styles.scrollContent}>
<Text style={styles.header}>InputAccessoryView 例 (iOSのみ)</Text>
<View style={styles.inputGroup}>
<Text style={styles.label}>テキスト入力1:</Text>
<TextInput
style={styles.input}
value={textInput1}
onChangeText={setTextInput1}
placeholder="ここに何か入力してください..."
// iOSの場合、InputAccessoryView との連携に inputAccessoryViewID を使用
inputAccessoryViewID={accessoryViewID} // nativeIDと同じ値を設定
/>
</View>
<View style={styles.inputGroup}>
<Text style={styles.label}>テキスト入力2:</Text>
<TextInput
style={styles.input}
value={textInput2}
onChangeText={setTextInput2}
placeholder="別の入力を試してください..."
inputAccessoryViewID={accessoryViewID} // 同じ accessoryViewID を使用
/>
</View>
{/* スクロール可能にするためのダミーコンテンツ */}
<View style={{ height: 300, backgroundColor: '#eee', justifyContent: 'center', alignItems: 'center' }}>
<Text>下にスクロールして、InputAccessoryView がキーボードに追従するか確認してください。</Text>
</View>
</ScrollView>
{/* InputAccessoryView の定義 (iOS専用) */}
{Platform.OS === 'ios' && (
<InputAccessoryView nativeID={accessoryViewID}>
<View style={styles.accessoryContainer}>
<Button title="テキスト1をクリア" onPress={() => clearInput(setTextInput1)} />
<Button title="テキスト2をクリア" onPress={() => clearInput(setTextInput2)} />
<Button title="Done" onPress={() => { /* キーボードを閉じるなどの処理 */ }} />
</View>
</InputAccessoryView>
)}
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
scrollContent: {
padding: 20,
paddingBottom: 100, // InputAccessoryView のためのスペースを確保
},
header: {
fontSize: 20,
fontWeight: 'bold',
marginBottom: 30,
textAlign: 'center',
},
inputGroup: {
marginBottom: 20,
},
label: {
fontSize: 16,
fontWeight: 'bold',
marginBottom: 5,
},
input: {
height: 50,
borderColor: '#ccc',
borderWidth: 1,
borderRadius: 8,
paddingHorizontal: 12,
backgroundColor: '#fff',
fontSize: 16,
},
accessoryContainer: {
flexDirection: 'row',
justifyContent: 'space-around',
alignItems: 'center',
height: 44,
backgroundColor: '#f0f0f0',
borderTopWidth: 1,
borderTopColor: '#ccc',
paddingHorizontal: 10,
},
});
export default InputAccessoryExample;
Platform.OS === 'ios'
で、iOSでのみInputAccessoryView
をレンダリングするように条件分岐しています。- これにより、どちらかの
TextInput
がフォーカスされた際に、同じInputAccessoryView
(カスタムツールバー) がキーボードの上に表示されるようになります。 - 各
TextInput
にはinputAccessoryViewID={accessoryViewID}
を設定しています。 InputAccessoryView
にはnativeID={accessoryViewID}
を設定しています。accessoryViewID
という定数で、InputAccessoryView
とTextInput
を関連付けるためのIDを定義しています。
アクセシビリティ関連の代替
nativeID
が主に accessibilityLabelledBy
と組み合わせて使われる場面での代替方法です。
-
accessibilityRole の使用
要素が果たす役割をスクリーンリーダーに伝えるためにaccessibilityRole
を使用します。これにより、特定のUI要素が何であるか(例: ボタン、ヘッダー、リンクなど)を明確にできます。直接nativeID
の代替とはなりませんが、アクセシビリティの文脈で要素を適切にマークアップする際に重要です。<Text accessibilityRole="header" style={styles.sectionHeader}> 個人情報 </Text>
利点
要素のセマンティックな意味を正確に伝え、スクリーンリーダーのユーザー体験を向上させる。 欠点:nativeID
のように要素間の明示的な関連付けを提供するものではない。 -
Text のネスト(入れ子構造)
React Native のText
コンポーネントは、他のText
コンポーネントを入れ子にすることができます。これにより、異なるスタイルを適用したり、セマンティックなグループ化を行ったりできます。視覚的なラベルと入力フィールドが近接している場合、スクリーンリーダーは自動的に関連付けて読み上げることがあります。<View style={styles.inputGroup}> <Text style={styles.label}> ユーザー名: <TextInput style={styles.input} value={username} onChangeText={setUsername} placeholder="ユーザー名を入力" autoCapitalize="none" /> </Text> </View>
利点
nativeID
を使う必要がなく、コードが簡潔になる場合がある。 欠点: すべてのプラットフォームやスクリーンリーダーで常に期待通りの読み上げになるとは限らない。特に複雑なUIの場合、アクセシビリティの挙動が予測しづらくなる可能性がある。accessibilityLabelledBy
のように明示的な関連付けではないため、より堅牢なアクセシビリティが求められる場合には不十分な場合がある。 -
accessibilityLabel の直接使用
最も直接的な代替方法です。Text
コンポーネントが単独でラベルとして機能する場合や、複雑な構造でない場合は、TextInput
などに直接accessibilityLabel
を設定するだけで十分な場合があります。スクリーンリーダーはこのラベルを読み上げます。// nativeID を使用しない場合 <TextInput style={styles.input} value={username} onChangeText={setUsername} placeholder="ユーザー名を入力" accessibilityLabel="ユーザー名" // 直接ラベルを設定 autoCapitalize="none" />
利点
コードがシンプルになり、nativeID
の重複を気にする必要がない。 欠点: ラベルとなるText
コンポーネントが視覚的に存在する場合、スクリーンリーダーがそのText
とTextInput
の両方を読み上げてしまう可能性があり、冗長になることがある。accessibilityLabelledBy
のように、視覚的なラベルとアクセシビリティラベルを紐付ける厳密な意味合いが薄い。
InputAccessoryView 関連の代替 (iOS)
InputAccessoryView
は nativeID
と inputAccessoryViewID
の組み合わせで機能するため、これに対する直接的な代替は非常に限定的です。基本的に、この機能を使う場合は nativeID
を使うのが推奨される方法です。
しかし、もし InputAccessoryView
が特定の TextInput
に常に紐づくのではなく、キーボード表示時に汎用的に表示されるツールバーを想定しているのであれば、以下のようなアプローチが考えられます。
-
KeyboardAvoidingView とカスタムコンポーネントの使用
これはInputAccessoryView
の代替というよりは、Androidを含むクロスプラットフォームでキーボードに追従するUIを実現する方法です。カスタムのツールバーコンポーネントを作成し、KeyboardAvoidingView
の内部に配置することで、キーボードの表示に合わせてそのコンポーネントが移動するようにします。import React, { useState } from 'react'; import { View, Text, TextInput, StyleSheet, Button, Platform, KeyboardAvoidingView, ScrollView } from 'react-native'; const CustomToolbar = ({ onClear }) => ( <View style={toolbarStyles.container}> <Button title="クリア" onPress={onClear} /> <Button title="閉じる" onPress={() => { /* キーボードを閉じる処理など */ }} /> </View> ); const KeyboardAvoidingExample = () => { const [text, setText] = useState(''); return ( <KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : 'height'} style={styles.container} keyboardVerticalOffset={Platform.OS === 'ios' ? 0 : 0} // 必要に応じて調整 > <ScrollView contentContainerStyle={styles.scrollContent}> <Text style={styles.header}>KeyboardAvoidingView とカスタムツールバー</Text> <Text style={styles.bodyText}>スクロールして、一番下の入力フィールドを試してください。</Text> {/* ダミーコンテンツ */} {[...Array(10)].map((_, i) => ( <View key={i} style={styles.dummyItem}> <Text>リストアイテム {i + 1}</Text> </View> ))} <View style={styles.inputGroup}> <Text style={styles.label}>入力フィールド:</Text> <TextInput style={styles.input} value={text} onChangeText={setText} placeholder="テキストを入力..." /> </View> </ScrollView> {/* キーボードに追従させたいカスタムツールバー */} <CustomToolbar onClear={() => setText('')} /> </KeyboardAvoidingView> ); }; const styles = StyleSheet.create({ container: { flex: 1, }, scrollContent: { flexGrow: 1, padding: 20, justifyContent: 'flex-end', // コンテンツを下に寄せる }, header: { fontSize: 20, fontWeight: 'bold', marginBottom: 20, textAlign: 'center', }, bodyText: { marginBottom: 20, textAlign: 'center', }, dummyItem: { height: 60, backgroundColor: '#f0f0f0', marginBottom: 10, justifyContent: 'center', alignItems: 'center', }, inputGroup: { marginTop: 20, marginBottom: 10, }, label: { fontSize: 16, fontWeight: 'bold', marginBottom: 5, }, input: { height: 50, borderColor: '#ccc', borderWidth: 1, borderRadius: 8, paddingHorizontal: 12, backgroundColor: '#fff', fontSize: 16, }, }); const toolbarStyles = StyleSheet.create({ container: { flexDirection: 'row', justifyContent: 'space-around', alignItems: 'center', backgroundColor: '#e0e0e0', paddingVertical: 10, borderTopWidth: 1, borderColor: '#ccc', }, }); export default KeyboardAvoidingExample;
利点
クロスプラットフォームでキーボード追従UIを実現できる。InputAccessoryView
が提供しない柔軟なレイアウトが可能。 欠点:InputAccessoryView
のようなネイティブレベルのキーボードとの統合ではないため、一部の挙動(例: キーボードのドラッグでツールバーが連動する)は再現が難しい場合がある。 -
TextInput を InputAccessoryView で直接ラップする
これは、InputAccessoryView
のドキュメントにも記載されている「Sticky text inputs」のシナリオです。InputAccessoryView
の中にTextInput
を直接含めることで、nativeID
を使わずにInputAccessoryView
を特定のTextInput
に紐付けることができます。ただし、この場合、そのInputAccessoryView
はそのTextInput
専用になります。import React, { useState } from 'react'; import { InputAccessoryView, TextInput, Button, View, Platform, StyleSheet } from 'react-native'; const StickyTextInputExample = () => { const [message, setMessage] = useState(''); return ( <View style={styles.container}> {/* 他のコンテンツ */} <Text style={styles.bodyText}>メッセージを送信できます。</Text> {Platform.OS === 'ios' && ( <InputAccessoryView> {/* nativeID を設定しない */} <View style={styles.accessoryContainer}> <TextInput style={styles.input} value={message} onChangeText={setMessage} placeholder="メッセージを入力..." multiline /> <Button title="送信" onPress={() => { Alert.alert('送信', message); setMessage(''); }} /> </View> </InputAccessoryView> )} </View> ); }; const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'flex-end', // 下部に固定されるように paddingBottom: Platform.OS === 'ios' ? 0 : 20, // Androidの場合の余白 }, bodyText: { flex: 1, textAlign: 'center', paddingTop: 50, }, accessoryContainer: { flexDirection: 'row', alignItems: 'center', backgroundColor: '#f0f0f0', paddingVertical: 8, paddingHorizontal: 10, borderTopWidth: 1, borderColor: '#ccc', }, input: { flex: 1, borderColor: '#ccc', borderWidth: 1, borderRadius: 20, paddingHorizontal: 15, paddingVertical: 8, marginRight: 10, backgroundColor: '#fff', maxHeight: 120, // マルチライン対応 }, }); export default StickyTextInputExample;
利点
nativeID
が不要。特定のTextInput
とツールバーが一体化しているようなUIで自然。 欠点: 複数のTextInput
で同じツールバーを共有するような複雑なシナリオには向かない。キーボードの表示/非表示に完全に追従させるためのレイアウト調整が必要になる場合がある。
テストID (testID) の使用
nativeID
はネイティブ統合やアクセシビリティが主な目的ですが、要素の一意な識別という点では testID
も似た役割を持ちます。ただし、testID
は主に自動テスト(例: Detox, Appium)で要素を特定するために使用されます。
<Text testID="welcomeText">
ようこそ!
</Text>
<Button
testID="loginButton"
title="ログイン"
onPress={() => console.log('ログインボタンが押されました')}
/>
利点
テストコードから簡単に要素を特定できる。
欠点: nativeID
が持つアクセシビリティや InputAccessoryView
との直接的な連携機能は持たない。本番環境のアプリの動作に直接影響を与えることは少ない。
Text#nativeID
は、その名の通り「ネイティブID」として特定のネイティブ連携を目的としたプロパティです。特にアクセシビリティの accessibilityLabelledBy
や iOS の InputAccessoryView
との連携には非常に有効であり、多くの場合、推奨されるアプローチです。
しかし、以下のような場合は代替手段を検討することもできます。
- 自動テストでの要素識別
testID
。 - 汎用的なキーボード追従UI(Androidも含む)
KeyboardAvoidingView
とカスタムコンポーネント。 - 単純なアクセシビリティの読み上げ
accessibilityLabel
の直接使用やText
の入れ子。