how to pass svg as a prop to a pressable component

11.5k views Asked by At

I'm using lot of svg images with the help of these two libraries

"react-native-svg": "^12.1.0",
"react-native-svg-transformer": "^0.14.3",

Then I can able to import and use svg images like below.

import Logo from '../assets/svg/img.svg';
...
...
<Logo height={60} />
...

The below is my custom button

***imaginary part // import Logo from '../assets/svg/img.svg';

const ButtonPressable = (props) => {
  return (
    <View>
      <Pressable
        style={[
          props.backgroundColor
            ? {backgroundColor: props.backgroundColor}
            : {backgroundColor: '#0077b6'},
        ]}>
        <Text>
          {props.text ? props.text : ''}
        </Text>

***imaginary part // <Logo height={60} />

      </Pressable>
    </View>
  );
};

I'm using above component like below

<ButtonPressable text="Login" backgroundColor="red" />

If you look at the imaginary part in above code. With that way, I can show svg images inside a component. But, I need to display svg images as a prop like below.

<ButtonPressable text="Login" backgroundColor="red" svg="../assets/svg/img.svg" />

How to pass svg path as a prop and display inside a component ?

4

There are 4 answers

1
Sameer Kumar Jain On BEST ANSWER

Here is an example of how to pass SVG imported from the main component. The idea is ButtonPressable will have a prop, svg, it could be anything but it can be SVG as well. Please modify ButtonPressable as below

const ButtonPressable = (props) => {
  return (
    <View>
      <Pressable
        style={[
          props.backgroundColor
            ? {backgroundColor: props.backgroundColor}
            : {backgroundColor: '#0077b6'},
        ]}>
        <Text>
          {props.text ? props.text : ''}
        </Text>

{props.svg? <props.svg height={60} /> : null}

      </Pressable>
    </View>
  );
};

and then import them anywhere like this and pass SVG

import Logo from '../assets/svg/img.svg';
<ButtonPressable text="Login" backgroundColor="red" svg={Logo} />

This will keep ButtonPressable reusable.

0
senthil balaji On

There are multiple ways you could use SVG in your project,

  1. converting SVG to font files and importing them in your project. I haven't tried this as you will have to do this process every time you have to add one more icon.

  2. use react-native-svg-transformer, I have myself used this, and was easy to implement (though not tried in Expo). Documentation is clear on how to implement in the project.

And you can create 2 files,

  1. export all the svg's
import LeftArrowIcon from "@src/assets/svg/leftArrow.svg";

export const IconFiles = {
  LeftArrowIcon
};

export const IconNames = {
   LEFT_ARROW_ICON: "LeftArrowIcon", // value should as same as icon fileimport
};

  1. A single common component for Icons (based on svgs)
// icon.tsx
import { IconFiles } from "@src/themes/icons";

// props: {iconName: string} example: LEFT_ARROW_ICON
export default (props) => {
  const I = IconFiles[`${props.iconName}`];
  return (
    <I width={defaultWidth || fromProps} height={defaultHeight || fromProps} />
  );
};

And eventually in your ButtonComponent,

const ButtonPressable = (props) => {
  return (
    <View>
      <Pressable
        style={[
          props.backgroundColor
            ? {backgroundColor: props.backgroundColor}
            : {backgroundColor: '#0077b6'},
        ]}>
        <Text>
          {props.text ? props.text : ''}
        </Text>
       <Icon iconName={props.iconName} />
      </Pressable>
    </View>
  );
};

And in your parent component, you could use it like,

<ButtonPressable 
  text="Login" 
  backgroundColor="red" 
  iconName={IconNames.LEFT_ARROW_ICON} 
/>
1
Osama Sayed On

How about you do that?

<img src={require(props.svg)} alt="Logo" height={60} />
2
Glitch_Znab On

Convert your SVG to JSX. you can then use that as an icon component.

you can use this SVG 2 JSX or SVGR Playground

For example below is a left arrow svg.

<svg xmlns="http://www.w3.org/2000/svg" width="20" height="16.327" viewBox="0 0 20 16.327"><path d="M-9.974-7.735a.988.988,0,0,0,.334.722L-2.489.127a.982.982,0,0,0,.7.3A.918.918,0,0,0-.841-.5a.943.943,0,0,0-.269-.679L-3.523-3.631l-3.63-3.306,2.606.162H9.078a.913.913,0,0,0,.948-.959.913.913,0,0,0-.948-.959H-4.546l-2.6.162,3.619-3.306,2.412-2.456a.961.961,0,0,0,.269-.679.918.918,0,0,0-.948-.926.964.964,0,0,0-.722.323L-9.64-8.456A.988.988,0,0,0-9.974-7.735Z" transform="translate(9.974 15.898)"/></svg>

then you can use the above link and covert it to a JSX.

import * as React from 'react';
import Svg, { Path } from 'react-native-svg';

export interface IconLeftArrowProps {
  width?: number;
  height?: number;
  color?: string;
}

/**
 * IconLeftArrow
 * Base svg file
 * assets/images/svgsSrc/icon_arrow_left.svg
 * @param
 * width   {Number} [ svg width size,  default size 20 ]
 * height  {Number} [ svg height size, default size 16.327 ]
 * color   {String} [ svg fill color,  default color BLACK(#000000) ]
 */
const IconLeftArrow: React.FC<IconLeftArrowProps> = ({
  width = 20 ,
  height = 16.327 ,
  color = #000000,
}) => (
  <Svg width={width} height={height} viewBox="0 0 20 16.327">
    <Path
      fill={color}
      d="M-9.974-7.735a.988.988,0,0,0,.334.722L-2.489.127a.982.982,0,0,0,.7.3A.918.918,0,0,0-.841-.5a.943.943,0,0,0-.269-.679L-3.523-3.631l-3.63-3.306,2.606.162H9.078a.913.913,0,0,0,.948-.959.913.913,0,0,0-.948-.959H-4.546l-2.6.162,3.619-3.306,2.412-2.456a.961.961,0,0,0,.269-.679.918.918,0,0,0-.948-.926.964.964,0,0,0-.722.323L-9.64-8.456A.988.988,0,0,0-9.974-7.735Z"
      transform="translate(9.974 15.898)"
    />
  </Svg>
);

export default IconLeftArrow;

I can't say for sure that the converters work perfectly as I also have faced issues. But if it does not work try to Change svg to Svg, path to Path and so on.

Then you can just import them and use them.