Check out "Do you speak JavaScript?" - my latest video course on advanced JavaScript.
Language APIs, Popular Concepts, Design Patterns, Advanced Techniques In the Browser

ReactNative: using SVG as a button

Just recently I started using ReactNative. I've been using React for years but this thing is a whole new world. There are tons of basic stuff which I don't know how to do. Using an SVG as a button is one of them. Find my solution below and expect more short #reactnative blog post soon.

First, we should mention that we can't just copy-paste the SVG code in our ReactNative project and use it. We have to use react-native-svg package. My SVG for example looks like this:

import Svg, { Path } from "react-native-svg";

const lineProps = {
  strokeOpacity: 1,
  strokeWidth: 1,
  strokeLineCap: "round",
  strokeLineJoin: "round",
};
function Button({ size }) {
  return (
    <Svg width={size} height={size} viewBox="0 0 122.88 122.88" {...lineProps}>
      <Path d="M61.44,0c16.966,0,32.326,6.877,43.445,17.995s17.996,26.479,17.996,43.444c0,16.967-6.877,32.327-17.996,43.445 S78.406,122.88,61.44,122.88c-16.966,0-32.326-6.877-43.444-17.995S0,78.406,0,61.439c0-16.965,6.877-32.326,17.996-43.444 S44.474,0,61.44,0L61.44,0z M34.556,67.179c-1.313-1.188-1.415-3.216-0.226-4.529c1.188-1.313,3.216-1.415,4.529-0.227L52.3,74.611 l31.543-33.036c1.223-1.286,3.258-1.336,4.543-0.114c1.285,1.223,1.336,3.257,0.113,4.542L54.793,81.305l-0.004-0.004 c-1.195,1.257-3.182,1.338-4.475,0.168L34.556,67.179L34.556,67.179z M100.33,22.55C90.377,12.598,76.627,6.441,61.44,6.441 c-15.188,0-28.938,6.156-38.89,16.108c-9.953,9.953-16.108,23.702-16.108,38.89c0,15.188,6.156,28.938,16.108,38.891 c9.952,9.952,23.702,16.108,38.89,16.108c15.187,0,28.937-6.156,38.89-16.108c9.953-9.953,16.107-23.702,16.107-38.891 C116.438,46.252,110.283,32.502,100.33,22.55L100.33,22.55z" />
    </Svg>
  );
}

This will be rendered properly but if we try adding onClick or onPress to the <Svg> component we will see that it doesn't work. We have to use some sort of touchable ReactNative component. And there are a few ones that are specifically made for this purpose. I decided to use <TouchableHighlight>. So, my component became:

import { TouchableHighlight } from "react-native";

function Button({ onPress, size }) {
  return (
    <TouchableHighlight onPress={onPress}>
      <Svg width={size} height={size} viewBox="0 0 122.88 122.88" {...lineProps}>
        <Path d="..." />
      </Svg>
    </TouchableHighlight>
  );
}

This works but has one big problem - the user needs to click on the exact SVG lines. The transparent bits of the icon are not clickable. To solve this problem we have to wrap our SVG into a View component. Like so:

function Button({ onPress }) {
  return (
    <TouchableHighlight onPress={onPress}>
      <View style={{ width: size, height: size }}>
        <Svg width={size} height={size} viewBox="0 0 122.88 122.88" {...lineProps}>
          <Path d="..." />
        </Svg>
      </View>
    </TouchableHighlight>
  );
}

With this, the icon is rendering and is clickable.

In my app I had to extend the code above to cover a few needs. Like for example having a default size and passing the color of the icon from the outside. Plus it is all TypeScript so here's the full component in case you need something similar:

import React from "react";
import { TouchableHighlight, View, GestureResponderEvent } from "react-native";
import Svg, { Path } from "react-native-svg";

const COLORS = {
  green: "#86d98c",
};

const lineProps = {
  strokeOpacity: 1,
  strokeWidth: 1,
  strokeLineCap: "round",
  strokeLineJoin: "round",
};

export function Button({
  color,
  size,
  onPress,
}: {
  color: string;
  size: number;
  onPress: (e: GestureResponderEvent) => void;
}) {
  return (
    <TouchableHighlight onPress={onPress}>
      <View style={{ width: size, height: size }}>
        <Svg width={size} height={size} viewBox="0 0 122.88 122.88" fill={COLORS.green} {...lineProps} stroke={color}>
          <Path d="..." />
        </Svg>
      </View>
    </TouchableHighlight>
  );
}

OK.defaultProps = {
  size: 50,
  color: COLORS.green,
  onPress: () => {},
};
If you enjoy this post, share it on Twitter, Facebook or LinkedIn.