28

triangle

I'm working on an app that uses triangles that overlay other containers/divs. Had that solved with CSS before:

.triangle:after {
  content: "";
  display: block;
  position: absolute;
  top: 15px;
  left: -15px;
  width: 0;
  border-width: 0px 0px 15px 15px;
  border-style: solid;
}

but that doesn't work in React any more. What's a solution here?

TylerH
  • 20,799
  • 66
  • 75
  • 101
Patrick
  • 7,903
  • 11
  • 52
  • 87

6 Answers6

56

It is still possible to draw triangles in React Native using the CSS trick. I wrote a class to encapsulate this: https://github.com/Jpoliachik/react-native-triangle

If you'd like to write it yourself, I used this tool: http://apps.eky.hk/css-triangle-generator/ to generate the triangle I wanted and modify the styles to React Native syntax.

For example, an Isosceles triangle 90x90 pointing up in CSS reads:

width: 0;
height: 0;
border-style: solid;
border-width: 0 45px 90px 45px;
border-color: transparent transparent #007bff transparent;

But in React Native the styles would be:

triangle: {
     width: 0,
     height: 0,
     backgroundColor: 'transparent',
     borderStyle: 'solid',
     borderTopWidth: 0,
     borderRightWidth: 45,
     borderBottomWidth: 90,
     borderLeftWidth: 45,
     borderTopColor: 'transparent',
     borderRightColor: 'transparent',
     borderBottomColor: 'red',
     borderLeftColor: 'transparent',
   },
Jpoliachik
  • 2,558
  • 2
  • 24
  • 23
21
render() {
    return (
        <View style={[styles.triangle,styles.arrowUp]}/>
    );
}

And styles

const styles = {
    triangle: {
        width: 0,
        height: 0,
        backgroundColor: 'transparent',
        borderStyle: 'solid',
    },
    arrowUp: {
        borderTopWidth: 0,
        borderRightWidth: 30,
        borderBottomWidth: 30,
        borderLeftWidth: 30,
        borderTopColor: 'transparent',
        borderRightColor: 'transparent',
        borderBottomColor: "tomato",
        borderLeftColor: 'transparent',
    },
    arrowRight: {
        borderTopWidth: 30,
        borderRightWidth: 0,
        borderBottomWidth: 30,
        borderLeftWidth: 30,
        borderTopColor: 'transparent',
        borderRightColor: 'transparent',
        borderBottomColor: 'transparent',
        borderLeftColor: "tomato",
    },
    arrowDown: {
        borderTopWidth: 30,
        borderRightWidth: 30,
        borderBottomWidth: 0,
        borderLeftWidth: 30,
        borderTopColor: "tomato",
        borderRightColor: 'transparent',
        borderBottomColor: 'transparent',
        borderLeftColor: 'transparent',
    },
    arrowLeft: {
        borderTopWidth: 30,
        borderRightWidth: 30,
        borderBottomWidth: 30,
        borderLeftWidth: 0,
        borderTopColor: 'transparent',
        borderRightColor: "tomato",
        borderBottomColor: 'transparent',
        borderLeftColor: 'transparent',
    },
    arrowUpLeft: {
        borderTopWidth: 30,
        borderRightWidth: "tomato",
        borderBottomWidth: 0,
        borderLeftWidth: 0,
        borderTopColor: "tomato",
        borderRightColor: 'transparent',
        borderBottomColor: 'transparent',
        borderLeftColor: 'transparent',
    },
    arrowUpRight: {
        borderTopWidth: 0,
        borderRightWidth: "tomato",
        borderBottomWidth: 30,
        borderLeftWidth: 0,
        borderTopColor: 'transparent',
        borderRightColor: "tomato",
        borderBottomColor: 'transparent',
        borderLeftColor: 'transparent',
    },
    arrowDownLeft: {
        borderTopWidth: 30,
        borderRightWidth: 0,
        borderBottomWidth: 0,
        borderLeftWidth: "tomato",
        borderTopColor: 'transparent',
        borderRightColor: 'transparent',
        borderBottomColor: 'transparent',
        borderLeftColor: "tomato",
    },
    arrowDownRight: {
        borderTopWidth: 0,
        borderRightWidth: 0,
        borderBottomWidth: 30,
        borderLeftWidth: "tomato",
        borderTopColor: 'transparent',
        borderRightColor: 'transparent',
        borderBottomColor: "tomato",
        borderLeftColor: 'transparent',
    },
}

Source : https://github.com/Jpoliachik/react-native-triangle

Janne Annala
  • 25,928
  • 8
  • 31
  • 41
Mahdi Bashirpour
  • 17,147
  • 12
  • 117
  • 144
  • I used it, but in android it was giving rough edges. Followed the react native issues found the soln. https://stackoverflow.com/a/75083722/9377254 – Ajmal Hasan Jan 12 '23 at 05:26
2

For beginners:

Most of the people who are new to CSS are getting confused with this triangle shape, my answer could be lengthy but read it completely.

Actually drawing triangle by using CSS styles is due to the beauty of "Borders", if you guys look closely at the endings of the borders, you will find out that borders are not straight at their endings let me show you, by changing the color of each border.

container having borders

styles applied to above image are:

{
   height: 100px;
   width: 100px;
   border-style: solid;
   border-left-width: 10px;
   border-right-width: 10px;
   border-top-width: 10px;
   border-bottom-width: 10px;
  
   border-left-color: pink;
   border-right-color: red;
   border-top-color: gray;
   border-bottom-color: green;
}

Now observe the above image closely you will find that if you will increase border width it will look like a triangle to some extent.

After increasing border width from 10px to 50px we are getting these results :

<!DOCTYPE html>
<html>
<head>
<style>

div {
  height: 100px;
  width: 100px;
  border-style: solid;
  border-left-width: 50px;
  border-right-width: 50px;
  border-top-width: 50px;
  border-bottom-width: 50px;
  
  border-left-color: pink;
  border-right-color: red;
  border-top-color: gray;
  border-bottom-color: green;
}

</style>
</head>

<body>
<div>I'm a container having colorful borders of 50px each</div>
<p><strong>Note:</strong> All the borders are not straight at their endings</p>
</body>
</html>

Till now, we are able to understand it, but there is an issue we are not able to get the tip of the triangle, this is because we have space inside the container which is avoiding the tip of borders and producing flat surface rather than the tip.

To get rid of this space inside the container just set your height and width to 0px, and look at the results.

<!DOCTYPE html>
<html>
<head>
<style>
h1 {
  border-left-style: solid;
  border-left-width: medium;
}

div {
  height: 0px;
  width: 0px;
  border-style: solid;
  border-left-width: 50px;
  border-right-width: 50px;
  border-top-width: 50px;
  border-bottom-width: 50px;
  
  border-left-color: pink;
  border-right-color: red;
  border-top-color: gray;
  border-bottom-color: green;
}
</style>
</head>
<body>


<div></div>

<p><strong>Note:</strong> All the borders are not straight at their endings</p>

</body>
</html>

Till now we are almost done with our all work, now we can make any triangle, by playing with styles. If you want to make a triangle pointing up, then just give transparent color to right, left, and top border, like this:

{
   height: 0px;
   width: 0px;
   border-style: solid;
   border-left-width: 50px;
   border-right-width: 50px;
   border-top-width: 50px;
   border-bottom-width: 50px;
  
   border-left-color: transparent;
   border-right-color: transparent;
   border-top-color: transparent;
   border-bottom-color: green;
}

If you don't want space above the tip of the triangle then you know very well that space is consumed by "topBorder" having transparent color, you can get rid of that space by either giving "border-top-width:0px;" or by removing it from your style.

React Native

Same technique will be used in react-native, just write your styles in camelNotation e.g (borderTopWidth, borderBottonWidth ...)

For further I would like that you should play with code himself.

Reference: Image used in this post, was generated by using w3schools online code editor.

w3schools Code Editor

1

This will give proper smooth triangle on both platform: enter image description here

As per the requirement borderWidth and borderColor prop can be adjusted for different triangles.

Sample

<View style={{
    width: 0,
    height: 0,
    borderStyle: 'solid',
    overflow: 'hidden',
    borderTopWidth: 6,
    borderRightWidth: 4,
    borderBottomWidth: 0,
    borderLeftWidth: 4,
    borderTopColor:'blue',
    borderRightColor: 'transparent',
    borderBottomColor: 'transparent',
    borderLeftColor: 'transparent',)}
}} />

Example

  const PropertyMarker = () => (
    <View style={styles.shadowWrapper}>
      <View
        style={styles.backgroundMarkerView()}>
        <Text
          style={styles.selectedText()}>
          MARKER_TEXT
        </Text>
      </View>
      <View style={styles.arrowDown()} />
      <View
        style={styles.arrowDown2()}
      />
    </View>
  )

const styles = StyleSheet.create({
  shadowWrapper: {alignItems: 'center', },
  selectedText: (marginStart = 0, color = COLOR_BLACK_100) => ({
    color,
    ...fontSize.fontSizeExtraSmall(),
    ...fonts.fontFamilyBold(),
    lineHeight: 16,
    marginStart,
  }),
  backgroundMarkerView: (backgroundColor = COLOR_SECONDARY) => ({
    padding: 4,
    borderRadius: 8,
    backgroundColor,
    borderWidth: 1,
    borderColor: COLOR_WHITE,
  }),
  arrowDown: (borderTopColor = 'blue') => ({
    width: 0,
    height: 0,
    borderStyle: 'solid',
    overflow: 'hidden',
    borderTopWidth: 6,
    borderRightWidth: 4,
    borderBottomWidth: 0,
    borderLeftWidth: 4,
    borderTopColor,
    borderRightColor: 'transparent',
    borderBottomColor: 'transparent',
    borderLeftColor: 'transparent',
  }),
  arrowDown2: (borderTopColor = 'blue') => ({
    width: 0,
    height: 0,
    borderStyle: 'solid',
    overflow: 'hidden',
    borderTopWidth: 5,
    borderRightWidth: 3,
    borderBottomWidth: 0,
    borderLeftWidth: 3,
    borderTopColor,
    borderRightColor: 'transparent',
    borderBottomColor: 'transparent',
    borderLeftColor: 'transparent',
    marginTop: -7,
  }),
})

Ajmal Hasan
  • 885
  • 11
  • 9
0

Why not use a dedicated library? https://github.com/react-native-community/react-native-svg

Yaron Levi
  • 12,535
  • 16
  • 69
  • 118
-18

The best way to do this is to create an <Image> component and absolutely position it, similar to how you would a pure CSS triangle. If the triangle has a flat color, as opposed to a gradient or other pattern, you can set its color using the tintColor style property.

Example:

<Image
  source={require('image!triangle')}
  style={{tintColor: '#008080'}}
/>
ide
  • 19,942
  • 5
  • 64
  • 106