Nested Text, Vertical Align not working - React Native

12.6k views Asked by At

Ok, Let's make this simple. I've two Text components, one inside another. The first Text has fontSize of 60, and the nested one has fontSize of 20. As the font size varies, the nested Text sits base aligned. I want the nested Text vertically center aligned with the parent one.

Code

// @flow
import React, { Component } from 'react';
import { Text } from 'react-native';

type PropTypes = {}
export default class SampleVC extends Component<PropTypes> {
    render() {
        return (
            <Text style={{ fontSize: 60 }}>
                Big Text
                <Text style={{ fontSize: 20 }}>Small Text</Text>
            </Text>
        );
    }
}

Current Output

Current Ouput

Needed Output

enter image description here

I know this is a simple scenario, but as am new to react native , i can't figure it out. I've searched all over the web,but couldn't find any helpful resource.

7

There are 7 answers

2
Ravi Raj On BEST ANSWER

It's not possible to achieve what you're trying using just nested Text.

The Only option, use a View to wrap your texts like,

<View style={{ flexDirection: 'row', alignItems: 'center' }} >
  <Text style={{ fontSize: 60 }}>Big Text</Text>
  <Text style={{ fontSize: 20 }}>Small Text</Text>
</View>

And if you want to use it often, create your own custom component for the above like,

function CustomNextedText (props) {
  return (
    <View style={{ flexDirection: 'row', alignItems: 'center' }} >
      <Text style={{ fontSize: 60 }}>{props.bigText}</Text>
      <Text style={{ fontSize: 20 }}>{props.smallText}</Text>
    </View>
  );
}

Use it anywhere like any other react-native component,

 <CustomNextedText bigText='Big Text' smallText='Small Text'/>

Hope it helps.

0
cglacet On

That seems odd, but here is something that seems to do the job for me (using @Ali SabziNezhad's suggestion). It allows to share text props (like color) and alignement (center in this particular case)

function Component() {
    return (
        <CenterText style={{color: 'red'}}>
            Centered <Text style={{fontSize: 50}}>text</Text>
        </CenterText>
    );
}
export function CenterText({children, ...otherProps}: Text['props']) {
    return (
        <Text {...otherProps}>
            <View 
                style={{flexDirection: 'row', alignItems: 'center'}} 
                children={children} 
            />
        </Text>
    );
}

We could event have a more generic alignment text component:

export function AlignedText({children, alignItems, ...otherProps}: AlignedTextProps) {
    return (
        <Text {...otherProps}>
            <View 
                style={{flexDirection: 'row', alignItems: alignItems}} 
                children={children} 
            />
        </Text>
    );
}

type Alignment = 'baseline' | 'center' | 'flex-end' | 'flex-start' | 'stretch';
type AlignedTextProps = Text['props'] & {alignItems: Alignment};

Which we can then use to define CenterText:

export function CenterText(props: TextProps) {
    return <AlignedText alignItems='center' {...props} />;
}

Or directly as:

function Component() {
    return (
        <AlignedText style={{color: 'red'}} alignItems='center'>
            Centered <Text style={{fontSize: 50}}>text</Text>
        </AlignedText>
    );
}
0
JDune On

Since React-Native v0.63 you can render <View/> inside <Text/>, without providing explicit dimensions for the View. Release Notes

With the accepted answer, if your Big Text is long enough to span multiple lines, the small text will be vertically centered to the entire block of Big Text, rather than a specific line.

So here's an update to @Ali S's answer using the new functionality. Height is still required in order to vertically center the nested text, so it is set to the fontSize of the Big Text. Width can be omitted, so the length of the small text can now be dynamic.

function BigSmallText(props) {
    let bigFontSize = 40;
    return (
        <Text
            style={{
                fontSize: bigFontSize,
                lineHeight: bigFontSize,
            }}>
            A very long sentence that spans multiple lines
            <View
                style={{
                    flexDirection: 'row',
                    alignItems: 'center',
                    height: bigFontSize,
                }}>
                <Text
                    style={{
                        fontSize: 14,
                        paddingLeft: 10,
                    }}>
                    SMALL TEXT
                </Text>
                <Text
                    style={{
                        fontSize: 6,
                        paddingLeft: 10,
                    }}>
                    TINY TEXT
                </Text>
            </View>
        </Text>
    );
}
2
Nirmalsinh Rathod On

You can add both Text into View.

<View style={{alignItems: 'center', justifyContent: 'center'}}>
       <Text style={{ fontSize: 60, height:'100%' }}>Big Text</Text>                
       <Text style={{ fontSize: 20, height:'100%' }}>Small Text</Text>
</View>
0
Alby On
< View style={{flexDirection:'column'}}>


    <View style={{alignContent:'center'}}>

        <Text style={{fontSize:60}}>{props.bigText}</Text>

    </View>

    <View style={{alignContent:'center'}} >

        <Text style={{fontSize:20}}>{props.smallText}</Text>

     </View>

< /View>
1
Ali SabziNezhad On

You can wrap nested Text in a View but nested View must have width and height. If you do not have any problem with this constraint, this is a good solution.

<Text style={{ fontSize: 60 }}>
      Big Text
      <View style={{ height:40, width:100, justifyContent: 'center', alignItems: 'center' }}>
            <Text style={{ fontSize: 20 }}>Small Text</Text>
      </View>
</Text>
0
Daniel Givoni On

you can also define the smallText lineHeight to match the bigText:

render() {
    return (
        <Text style={{ fontSize: 60 }}>
            Big Text
            <Text style={{ fontSize: 20, lineHeight:60 }}>
                Small Text
            </Text>
        </Text>
    );
}