react-native
react-native copied to clipboard
[w3c] ☂️ Web Props umbrella issue
Add support for Web props to core components
Contingent on RFC feedback. This is the umbrella issue for basic React DOM / Web props support on React Native components, as described in this proposal: "RFC: Reduce fragmentation across platforms".
Each of the tasks listed below can be tackled with individual PRs that link back to this issue. Not every task has a known solution or implementation yet, so feel free to discuss implementation details in the comments. Each new prop should take priority over any existing equivalents.
Common props
These props should be supported by core components, i.e., <Image>
, <View>
, <Text>
, <TextInput>
, etc.
Prop aliases
- [x] Add
aria-label
alias foraccessibilityLabel
. https://github.com/facebook/react-native/pull/34502 - [x] Add
aria-labelledby
alias foraccessibilityLabelledBy
. https://github.com/facebook/react-native/pull/34725 - [x] Add
aria-modal
alias foraccessibilityViewIsModal
(iOS). https://github.com/facebook/react-native/pull/34506 - [x] Add
id
alias fornativeID
. https://github.com/facebook/react-native/pull/34522
Accessibility State. https://github.com/facebook/react-native/pull/34524
- [x] Add
aria-busy
alias foraccessibilityState.busy
. - [x] Add
aria-checked
alias foraccessibilityState.checked
.- [x] Support
mixed
value https://github.com/facebook/react-native/pull/34633
- [x] Support
- [x] Add
aria-disabled
alias foraccessibilityState.disabled
. - [x] Add
aria-expanded
alias foraccessibilityState.expanded
. - [x] Add
aria-selected
alias foraccessibilityState.selected
.
Accessibility Value. https://github.com/facebook/react-native/pull/34535
- [x] Add
aria-valuemax
alias foraccessibilityValue.max
. - [x] Add
aria-valuemin
alias foraccessibilityValue.min
. - [x] Add
aria-valuenow
alias foraccessibilityValue.now
. - [x] Add
aria-valuetext
alias foraccessibilityValue.text
.
Prop equivalents
- [x] Add
aria-hidden
. https://github.com/facebook/react-native/pull/34552- [x] Alias for
importantforAccessibility='no-hide-descendants'
(Android). - [x] Alias for
accessibilityElementsHidden
(iOS).
- [x] Alias for
- [x] Add
aria-live
. https://github.com/facebook/react-native/pull/34555- [x] Alias for
accessibilityLiveRegion
(Android). - [x] Map
aria-live='off'
toaccessibilityLiveRegion='none'
.
- [x] Alias for
- [x] Add
role
. https://github.com/facebook/react-native/pull/34538#issuecomment-1232918518 & https://github.com/facebook/react-native/pull/34976- [x] Alias for
accessibilityRole
but with full list of ARIA roles allowed. - [x] Map
role='slider'
toaccessibilityRole='adjustable'
- [x] Map
role='img'
toaccessibilityRole='image'
- [x] Map
role='presentation'
toaccessibilityRole='none'
- [x] Map
role='summary'
toaccessibilityRole='region'
- [ ] Add
role='option'
support.
- [x] Alias for
- [x] Add
tabIndex
. https://github.com/facebook/react-native/pull/34486- [x] Only support for
0
and-1
values only. - [x] Map
tabIndex={0}
tofocusable={true}
(Android) - [x] Map
tabIndex={-1}
tofocusable={false}
(Android)
- [x] Only support for
Example:
<View
aria-hidden={true}
aria-busy={false}
aria-label="Accessibility label"
aria-valuetext="Middle"
id="native-id"
role="slider"
tabIndex={0}
>
// same as
<View
accessibilityElementsHidden={true}
accessibilityLabel="Accessibility label"
accessibilityRole="adjustable"
accessibilityState={{ busy: false }}
accessibilityValue={{ text: "Middle" }}
focusable={true}
importantforAccessibility='no-hide-descendants'
nativeId="native-id"
>
<Image>
props
These props should be supported by <Image>
.
- [x] Add
alt
. https://github.com/facebook/react-native/pull/34550- [x] Support alternative text support.
- [x] Add
tintColor
prop to replace non-standardstyle.tintColor
. The tintColor style is currently forwarded to a native prop and should instead be exposed as a prop so that React Native for Web does not have to deopt styles for Image rendering. https://github.com/facebook/react-native/pull/34534#issuecomment-1232902094
These props are inter-related:crossOrigin
and referrerPolicy
should only apply if src
or srcSet
are defined; and src
should be ignored if a valid srcSet
is defined. The user-provided source
prop should be ignored if a valid src
or srcSet
prop is also defined.
https://github.com/facebook/react-native/pull/34481
- [x] Add
crossOrigin
.- [x] Potentially map
crossOrigin='use-credentials'
tosource.headers['Access-Control-Allow-Credentials'] = true
.
- [x] Potentially map
- [x] Add
height
. - [x] Add
referrerPolicy
.- [x] Potentially map
referrerPolicy
tosource.headers['Referrer-Policy'] = referrerPolicy
.
- [x] Potentially map
- [x] Add
src
.- [x] Map
src
tosource.uri
.
- [x] Map
- [x] Add
srcSet
.- [x] Map
srcSet='path1 x1, path1 x2'
tosource=[{ uri: path1, scale: 1 }, { uri: path2, scale: 2 }]
.
- [x] Map
- [x] Add
width
.
Example mapping to source
:
const { crossOrigin, height, referrerPolicy, src, srcSet, width } = props;
let source = null;
if (src != null) {
const headers = {};
if (crossOrigin === 'use-credentials') {
headers['Access-Control-Allow-Credentials'] = true;
}
if (referrerPolicy != null) {
headers['Referrer-Policy'] = referrerPolicy;
}
nextProps.progressiveRenderingEnabled = true;
source = { headers, height, uri: src, width };
}
if (srcSet != null) {
source = [];
const srcList = srcSet.split(', ');
srcList.forEach((src) => {
const [uri, xscale] = src.split(' ');
const scale = parseInt(xscale.split('x')[0], 10);
const headers = {};
if (crossOrigin === 'use-credentials') {
headers['Access-Control-Allow-Credentials'] = true;
}
if (referrerPolicy != null) {
headers['Referrer-Policy'] = referrerPolicy;
}
source.push({ headers, height, scale, uri, width });
});
}
Example:
<Image
alt="Alternative text"
crossOrigin="use-credentials"
height={300}
referrerPolicy="origin"
srcSet="https://image.png 1x, https://image2.png 2x"
width={500}
>
// same as
<Image
source={[
{
uri: "https://image.png",
scale: 1,
height: 300,
headers: {
'Access-Control-Allow-Credentials': true,
'Referrer-Policy': 'origin'
},
width: 500
}
{
uri: "https://image2.png",
scale: 2,
height: 300,
headers: {
'Access-Control-Allow-Credentials': true,
'Referrer-Policy': 'origin'
},
width: 500
}
]}
>
<TextInput>
props
These props should be supported by <TextInput>
.
- [x] Redefine
autoComplete
. https://github.com/facebook/react-native/pull/34523- Unify values for Android (
autoComplete
) and iOS (textContentType
) with Web (autoComplete
). - See code below for example mapping.
- Unify values for Android (
- [x] Add
enterKeyHint
. https://github.com/facebook/react-native/pull/34482- [x] Map to equivalent
returnKeyType
values. - [x] Map
enterKeyHint === 'enter'
toreturnKeyType = 'default'
- [x] Map
enterKeyHint === 'done'
toreturnKeyType = 'done'
- [x] Map
enterKeyHint === 'go'
toreturnKeyType = 'go'
- [x] Map
enterKeyHint === 'next'
toreturnKeyType = 'next'
- [x] Map
enterKeyHint === 'previous'
toreturnKeyType = 'previous'
- [x] Map
enterKeyHint === 'search'
toreturnKeyType = 'search'
- [x] Map
enterKeyHint === 'send'
toreturnKeyType = 'send'
- [x] Map to equivalent
- [x] Add
inputMode
. https://github.com/facebook/react-native/pull/34460- [x] Map to equivalent
keyboardType
values. - [x] Map
inputMode === 'none'
tokeyboardType = 'none'
- [x] Map
inputMode === 'text'
tokeyboardType = 'text'
- [x] Map
inputMode === 'decimal'
tokeyboardType = 'decimal-pad'
- [x] Map
inputMode === 'email'
tokeyboardType = 'email-address'
- [x] Map
inputMode === 'numeric'
tokeyboardType = 'numeric'
- [x] Map
inputMode === 'search'
tokeyboardType = 'search'
- [x] Map
inputMode === 'tel'
tokeyboardType = 'phone-pad'
- [x] Map
inputMode === 'url'
tokeyboardType = 'url'
- [x] Map to equivalent
- [x] Add
readOnly
. https://github.com/facebook/react-native/pull/34444- [x] Map
readOnly={false}
toeditable={true}
. - [x] Map
readOnly={true}
toeditable={false}
.
- [x] Map
- [x] Add
rows
(formultiline={true}
). https://github.com/facebook/react-native/pull/34488- [x] Map
rows
tonumberOfLines
(Android).
- [x] Map
Example autoComplete
mapping:
// https://reactnative.dev/docs/textinput#autocomplete-android
const autoCompleteAndroid = {
// web: android
'address-line1': 'postal-address-region',
'address-line2': 'postal-address-locality',
bday: 'birthdate-full',
'bday-day': 'birthdate-day',
'bday-month': 'birthdate-month',
'bday-year': 'birthdate-year',
'cc-csc': 'cc-csc',
'cc-exp': 'cc-exp',
'cc-exp-month': 'cc-exp-month',
'cc-exp-year': 'cc-exp-year',
'cc-number': 'cc-number',
country: 'postal-address-country',
'current-password': 'password',
email: 'email',
name: 'name',
'additional-name': 'name-middle',
'family-name': 'name-family',
'given-name': 'name-given',
'honorific-prefix': 'namePrefix',
'honorific-suffix': 'nameSuffix',
'new-password': 'password-new',
off: 'off',
'one-time-code': 'sms-otp',
'postal-code': 'postal-code',
sex: 'gender',
'street-address': 'street-address',
tel: 'tel',
'tel-country-code': 'tel-country-code',
'tel-national': 'tel-national',
username: 'username'
};
// https://reactnative.dev/docs/textinput#textcontenttype-ios
const autoCompleteIOS = {
// web: ios
'address-line1': 'streetAddressLine1',
'address-line2': 'streetAddressLine2',
'cc-number': 'creditCardNumber',
'current-password': 'password',
country: 'countryName',
email: 'emailAddress',
name: 'name',
'additional-name': 'middleName',
'family-name': 'familyName',
'given-name': 'givenName',
nickname: 'nickname',
'honorific-prefix': 'name-prefix',
'honorific-suffix': 'name-suffix',
'new-password': 'newPassword',
off: 'none',
'one-time-code': 'oneTimeCode',
organization: 'organizationName',
'organization-title': 'jobTitle',
'postal-code': 'postalCode',
'street-address': 'fullStreetAddress',
tel: 'telephoneNumber',
url: 'URL',
username: 'username'
};
Examples:
<TextArea
autoComplete="email"
inputMode="email"
/>
// same as
<TextArea
autoComplete="email"
keyboardType="email-address"
textContentType="emailAddress"
/>
<TextArea
multiline
readOnly={true}
rows={3}
/>
// same as
<TextArea
editable={false}
multiline
numberOfLines={3}
/>
Documentation
- [x] Update react-native-website docs to include all these props. @gabrieldonadel has several PRs open for individual props, which we may want to consolidate into a single PR and add remaining props, so it can be merged in one commit.
See companion issue related to styles https://github.com/facebook/react-native/issues/34425
I'd love to help out. This would be my first real open source contribution. Is there anything I should be aware of in order to get started?
@necolas I've just opened a PR adding the readOnly
prop to the TextInput component (https://github.com/facebook/react-native/pull/34444), please let me know if this is what was expected or if it should be implemented using a different approach
@necolas just FYI I've opened a PR tackling the Add tabIndex
task here https://github.com/facebook/react-native/pull/34486
We have PRs either merged or open for every prop listed here except aria-hidden
, aria-live
, and alt
. Big thanks to everyone who has contributed patches so far. This work is also going to indirectly help make React Native for Web better.
If you're still looking to contribute to this wider effort to bridge the gap between React Native and React DOM, we also have some styling tasks https://github.com/facebook/react-native/issues/34425
The following would also be great to add:
-
mask
-
clip-path
-
shape-outside
-
filter
-
mix-blend-mode
The following would also be great to add
Presumably you meant to post this on the styles umbrella issue?
There has to be an idea of how to implement these features though. Almost everything I've listed to date has already been bridged in RNWeb or a shim I wrote internally, so there's not a lot of new native work needed. Once we have added support for the easy props and styles, people can start looking into how to implement features that require new native code to be written.
Presumably you meant to post this on the styles umbrella issue?
Ah, yep, posted on the wrong one.
Once we have added support for the easy props and styles, people can start looking into how to implement features that require new native code to be written.
Sounds good.
I also want to set expectations: for at least the next 6 months, Meta is unlikely to be able to commit engineers to work on new native features to expand CSS support (with the exception of flexbox-related changes to Yoga). But if contributors who want these CSS features can develop and test them, we will help to integrate the code and give credit where it is due. Thanks!
Question: what about data- attributes?
some headless web UI libraries make huge use of them to attach some "state" to DOM, I'm worried that they are not transferrable.
Are those supported?
One more task has been added, which is to update the react-native-website docs to include all these new props once all the PRs have been merged.
I think adding aria-labelledby
aliases for accessibilityLabelledBy
should be part of this Issue as well.
Good idea
I think role
support is missing from Text
(which appears to support accessibilityRole
): https://github.com/facebook/react-native/blob/main/Libraries/Text/TextProps.js
This logic in View
may need to be moved to a shared place so it can be used in Text
too
I think role="option"
is missing
I think
role
support is missing fromText
(which appears to supportaccessibilityRole
): https://github.com/facebook/react-native/blob/main/Libraries/Text/TextProps.jsThis logic in
View
may need to be moved to a shared place so it can be used inText
too
Hi @necolas, just FYI I've opened a PR (https://github.com/facebook/react-native/pull/34976) a couple days ago tackling this
I think role="option" is missing
Good spot. I'll add one more task to add option
.
Good spot. I'll add one more task to add
option
.
@necolas what should we map the role
option to? Should we add this new value natively on accessibilityRole as well?
It maps to nothing AFAICT, but needs to be included in the type for role
It maps to nothing AFAICT, but needs to be included in the type for
role
Got it, I've just opened a PR for that https://github.com/facebook/react-native/pull/35137
Hi @necolas, I saw that the Update [react-native-website](https://github.com/facebook/react-native-website/) docs to include all these props
task was marked as completed. I believe some props are still missing tho, is someone from Meta going to work on this or is it still pending?
My mistake. Unchecked it again
All the props listed here have been implemented. Thanks so much to everyone who helped here, especially @gabrieldonadel for helping from start to end!
I'm going complete some updates to RNWeb so that it allows these props too.
And then I will probably create a "Part 2" issue with a few more props from the RFC. I'll also be updating the RFC with more details about the Event and Element APIs, which will likely form new umbrella issues.
If you have suggestions for more W3C props we could implement, please comment on "RFC: Reduce fragmentation across platforms". I will start to publish updates to that RFC in the coming weeks. Thanks
👋 Been closely following along this work and just want to thank all of you for pushing this effort forward!
Quick question: are there plans to align implementation/typescript values for accessibility props? I'm seeing react-native uses boolean while @types/react uses Booleanish which allows boolean | 'true' | 'false'
@necolas I noticed that Touchable*
components doesn't have accessibilityLabelledBy
& aria-labelledby
props, is it expected ?