We have a custom renderer for span
tags but I can't find any way to force the span to full-width. I tried wrapping the custom renderer in a View
as well as applying all the usual React-Native styles without luck.
Given input HTML like below
<span>Hello</span><span>Goodbye</span>
How can we render it as below?
Hello
goodbye
Currently it renders inline like:
hello
goodbye
The custom renderer looks like this:
const renderers = {
span: RenderedSpan,
};
const RenderedSpan = props => {
return (
<Text>
Some hardcoded text
</Text>
);
};
I figured I'd finally found a solution for the issue when I came across an example
That inspired me to try this code to set the contentModel
to block
:
(still no dice)
const customHTMLElementModels = {
span: defaultHTMLElementModels.span.extend({
contentModel: HTMLContentModel.block,
}),
};
CodePudding user response:
React Native Capabilities
React Native has roughly two display algorithms: flex, and text-inline. Any element which has a Text
parent will be displayed with the text-inline algorithm, and all other elements will be displayed with the flex algorithm. The former severely limits the set of styles which will be supported, this is what you are stumbling on.
Elements inside text-inline will have the following styles ignored:
- Margins
- Percent-widths
- All flex rules
I suggest you play with a snippet like the one below to have a gist:
import React from 'react';
import {SafeAreaView, useWindowDimensions, View, Text} from 'react-native';
export default function App() {
const {width} = useWindowDimensions();
return (
<SafeAreaView style={{flex: 1}}>
<Text>
Hello world!
<View style={{ /* play with padding, margins, flex... etc! */ }}>
<Text>I'm inside a view!</Text>
</View>
How are you doing?
</Text>
</SafeAreaView>
);
}
Solution 1: force width
Hence, the only way we could achieve what you are looking for via styles would be to set its width
to the passed contentWidth
:
import React from 'react';
import {SafeAreaView, useWindowDimensions, View} from 'react-native';
import RenderHTML, {
CustomTextualRenderer,
useContentWidth,
} from 'react-native-render-html';
const htmlContent = `
<span>Hello</span><span>Goodbye</span>
`;
const RenderedSpan: CustomTextualRenderer = ({TDefaultRenderer, ...props}) => {
const width = useContentWidth();
return (
<View style={{width}}>
<TDefaultRenderer {...props} />
</View>
);
};
const renderers = {
span: RenderedSpan,
};
export default function App() {
const {width} = useWindowDimensions();
return (
<SafeAreaView style={{flex: 1}}>
<RenderHTML
renderers={renderers}
source={{html: htmlContent}}
contentWidth={width}
/>
</SafeAreaView>
);
}
Solution 2: use Block content model
You suggested setting the span
content model to block
and with the snippet you provided, it works great:
import React from 'react';
import {SafeAreaView, useWindowDimensions, View} from 'react-native';
import RenderHTML, {
defaultHTMLElementModels,
HTMLContentModel,
} from 'react-native-render-html';
const htmlContent = `
<span>Hello</span><span>Goodbye</span>
`;
const customHTMLElementModels = {
span: defaultHTMLElementModels.span.extend({
contentModel: HTMLContentModel.block,
}),
};
export default function App() {
const {width} = useWindowDimensions();
return (
<SafeAreaView style={{flex: 1}}>
<RenderHTML source={{html: htmlContent}} contentWidth={width} customHTMLElementModels={customHTMLElementModels} />
</SafeAreaView>
);
}
The block content model will force the render engine to guarantee rendered span
elements won't have any Text
ascendants, thus securing a flex column display. LINK TO SNACK
CodePudding user response:
Did you try something like this :
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
export default function App() {
const renderers = {
span: RenderedSpan,
};
const RenderedSpan = props => {
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor:"#ff0000"
},
});
return (
<View style={styles.container}>
<Text>Some hardcoded text</Text>
</View>
);
};
return <RenderedSpan/>;
}