First-class (partial) text selection support on mobile (iOS) for `<html.p />`, `<html.h1 />`, `<html.span />`, et al
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Aptitud para principiantes
- 35/100
- Tipo de issue
- Nueva funcionalidad
- Claridad
- Bastante claro
- Estado de actividad
- Tranquilo
- Stack tecnológico
- javascript, react-native
Línea de trabajo
Comienza con el punto de entrada createStrictDOMTextComponent y compáralo con createStrictDOMTextInputComponent; después, reproduce el ejemplo mínimo de Expo/iOS del issue. Rastrea cómo los elementos de texto HTML nativos se asignan a componentes de React Native y evalúa la estructura opt-in propuesta para selectable. El resultado debería proporcionar una selección de texto nativa parcial en iOS sin cambiar el comportamiento predeterminado ni el de la web.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Describe the feature request
On iOS (only mobile platform I've tested so far), let text-bearing html.* elements:
html.phtml.h1...html.h6html.lihtml.spanhtml.code- et al
...participate in the native partial-text-selection affordance:
- drag to extend a range
- selection handles
- magnifier
- ...and the system edit menu; i.e.:
- Copy
- Look Up
- Translate
- Share
- Speak
- Writing Tools
Same behaviour React Native for (Desktop) macOS already provides via react-native-macos's NSTextView (and that browsers provide on web).
iOS is the outlier.
Android: yet to be tested. (OpenHarmony, likely entirely out of scope).
Current behaviour
Setting userSelect: 'text' on a text-bearing html.* element on iOS surfaces the iOS edit menu on long-press, but only with Copy. There is no selection range: the menu opens directly, dragging does nothing, no magnifier, no handles. Tapping Copy copies the whole element's text rather than a chosen range.
Minimal reproduction (Expo SDK 55 + [email protected], iOS 16+):
import { html, css } from 'react-strict-dom';
const styles = css.create({
p: { fontSize: 16, lineHeight: 1.45, userSelect: 'text' },
});
export default function Demo() {
return (
<html.p style={styles.p}>
Long-press this paragraph on iOS. The system edit menu opens
immediately with only `Copy`. No selection handles, no
drag-to-extend, no magnifier. The same `html.p` on macOS
supports full partial selection.
</html.p>
);
}
Why it matters
The asymmetry breaks consistent UX across the platforms RSD targets:
| Platform | Partial selection | System edit menu |
|---|---|---|
| Web | ✅ browser default | ✅ browser default |
macOS (react-native-macos) |
✅ NSTextView default |
✅ AppKit default |
iOS (react-native) |
❌ | Copy only |
Android (react-native) |
❌ | ([likely] out of scope here) |
For any reader-oriented surface (articles, chat messages, notes, markdown viewers, quoted replies) partial selection is table stakes. Users who experience macOS and iOS in the same app are particularly badly served by the gap.
Root cause
html.p / html.h1 ... html.h6 / html.li / html.span / html.code all map to react-native's Text on native (createStrictDOMTextComponent → Text). React Native's iOS Text is RCTParagraphComponentView (Fabric) / RCTTextView (legacy): a custom UIView that draws via NSLayoutManager. It doesn't implement UITextInteraction, so iOS has nothing to attach selection handles to.
The well-known RN-iOS workaround for partial-text selection is <TextInput editable={false} multiline selectable />, backed by UITextView and inheriting full selection + native edit menu. RSD already maps html.input and html.textarea to TextInput via createStrictDOMTextInputComponent: the primitive is right there; it just isn't what static text elements compile to.
Proposed shapes (sketches, in increasing invasiveness)
-
New
selectableHTML prop, opt-in: RSD adds aselectableboolean prop to text elements; when true on iOS, the underlying renderer wraps the content in a read-onlyTextInput. Default false; web semantics unchanged.<html.p selectable>…</html.p> -
Render-mode escape hatch: a new prop or variant that lets a consumer opt into TextInput-backed rendering for paragraphs / headings they want fully selectable. More general than a single boolean
-
Map
userSelect: 'text'(or other) toTextInput-readonly on iOS automatically: most magical, most spooky-action-at-a-distance; possibly breaks consumers relying onText-specific layout behaviour thatTextInput-readonly approximates rather than matches
"1" seems like the cleanest first cut: opt-in, doesn't change defaults, matches the platform reality that "selectable static text on iOS" is a distinct rendering choice rather than a free property of Text.
Workarounds (naive assumptions...)
<TextInput editable={false} multiline selectable />used directly (canonical RN-iOS pattern, but bypasses RSD's semantic mapping)react-native-selectable-text: community library wrapping the above- Conditional renderers that swap RSD primitives for RN's
TextInputon iOS: works but pushes platform-divergence into consumer code
All of these work, but each lives outside RSD's surface. The gap is a consistent, RSD-supported way to mark static text as selectable that handles the platform divergence so consumers don't have to.
Related / "Prior Art"
- React Native issue #23147 (closed): original observation that selection ranges aren't exposed on
Text; the RN team's answer was effectively "useTextInputread-only," which is the right RSD-side answer if you accept that rendering choice - RSD's recent input-side
setSelectionRange/selectionStart/selectionEndpolyfill work (commit65e439b, Dec 2025) shows selection is on the roadmap on the input side; static-text selection is the natural companion
(Likely) Out of scope
- Editor/ cursor/keyboard navigation (these need
editable-true paths and are larger) - Android partial selection (related, but RN-Android has its own constraints; deserves a separate issue)
- Selection-event callbacks (
onSelectionChangeon static text): useful, but layerable on top of basic selection support
- Lenguaje dominante
- JavaScript
- Estrellas
- 3.6k
- Forks
- 208
- Métricas de merge de PR
- Sin PR fusionados en 30 d
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Sin plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de react/react-strict-dom
-
Outline styles aren't parsed in React NativePosiblemente ocupada @hoangvvo la tomó hace 145 días. Abiertobug
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
react/react-strict-dom#467 · 1 comentario ·
-
Missing disabled propAbierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
react/react-strict-dom#465 · 2 comentarios ·
-
postcss plugin re-transforms every included file on each rebuild under Turbopack (minutes-long HMR in large projects)Posiblemente ocupada @borisyankov la tomó hace 14 días. Abierto
Dificultad 5/5 Más de una semana Aptitud para principiantes 35/100
react/react-strict-dom#520 ·
-
css.defineVars() with kebab-case keys warns unrecognized custom property and fails to resolveAbiertobug
Dificultad 2/5 1-3 horas Aptitud para principiantes 35/100
react/react-strict-dom#505 · 2 reacciones ·
-
Button remains unclickable after disabled state changesPosiblemente ocupada @MoOx la tomó hace 128 días. Abiertobug
Dificultad 3/5 1-2 días Aptitud para principiantes 62/100
react/react-strict-dom#491 · 4 comentarios ·
Todos los issues de react/react-strict-dom
Issues similares
-
Dificultad 1/5 1-3 horas Aptitud para principiantes 67/100
Morni-Team/pkmessenger#44 · 4 comentarios ·
Los mantenedores suelen responder en 1 día
-
status/needs-triage type/bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
PKU-YuanGroup/OpenAI4S#218 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 62/100
debpalash/VoiceStudio#2678 ·
Los mantenedores suelen responder en 1 día
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 66/100
Los mantenedores suelen responder en 3 días