Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React: replace links in a text

What is the proper way to replace urls in a string and render them as links with React?

Say I have a string: 'hello http://google.com world', and I want it to render like: hello <a href="http://google.com">http://google.com</a> world

like image 944
ch1p_ Avatar asked Oct 20 '15 11:10

ch1p_


6 Answers

Ok, so this is how I done it.

class A extends React.Component {
  renderText() {
    let parts = this.props.text.split(re) // re is a matching regular expression
    for (let i = 1; i < parts.length; i += 2) {
      parts[i] = <a key={'link' + i} href={parts[i]}>{parts[i]}</a>
    }
    return parts
  }
  render() {
    let text = this.renderText()
    return (
      <div className="some_text_class">{text}</div>
    )
  }
}
like image 187
ch1p_ Avatar answered Nov 14 '22 20:11

ch1p_


There are NPM modules to handle this. Both of these depend on linkify-it (repo)

react-linkify (repo)

<Linkify>
  <div>react-linkify <span>(tasti.github.io/react-linkify/)</span></div>
    <div>React component to parse links (urls, emails, etc.) in text into clickable links</div>
  See examples at tasti.github.io/react-linkify/.
    <footer>Contact: [email protected]</footer>
</Linkify>

At time of writing, the current version is 1.0.0-alpha. It requires React 16. The repo has 14 open tickets and 17 open PRs. So that's not fantastic.

Version 0.2.2 allows much earlier versions but doesn't have link text decoration, etc.

react-native-hyperlink ( repo )

If you are using native (ie a phone app), it looks like the better of the two options. Code samples:

<Hyperlink linkDefault={ true }>
  <Text style={ { fontSize: 15 } }>
    This text will be parsed to check for clickable strings like https://github.com/obipawan/hyperlink and made clickable.
  </Text>
</Hyperlink>

<Hyperlink onLongPress={ (url, text) => alert(url + ", " + text) }>
  <Text style={ { fontSize: 15 } }>
    This text will be parsed to check for clickable strings like https://github.com/obipawan/hyperlink and made clickable for long click.
  </Text>
</Hyperlink>

<Hyperlink
  linkDefault
  injectViewProps={ url => ({
        testID: url === 'http://link.com' ? 'id1' : 'id2' ,
        style: url === 'https://link.com' ? { color: 'red' } : { color: 'blue' },
        //any other props you wish to pass to the component
  }) }
>
  <Text>You can pass props to clickable components matched by url.
    <Text>This url looks red https://link.com
  </Text> and this url looks blue https://link2.com </Text>
</Hyperlink>

References

  • https://github.com/facebook/react-native/issues/3148
  • REACT - How to replace URL strings to <a> elements and rendering it properly
like image 29
MustModify Avatar answered Nov 14 '22 20:11

MustModify


I ran into issues with every answer here, so I had to write my own:

// use whatever you want here
const URL_REGEX = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/;

const renderText = txt =>
  txt
    .split(" ")
    .map(part =>
      URL_REGEX.test(part) ? <a href={part}>{part} </a> : part + " "
    );
like image 10
Joe Roddy Avatar answered Nov 14 '22 21:11

Joe Roddy


Try this library, it does exactly you need: https://www.npmjs.com/package/react-process-string

An example from there:

const processString = require('react-process-string');

let config = [{
    regex: /(http|https):\/\/(\S+)\.([a-z]{2,}?)(.*?)( |\,|$|\.)/gim,
    fn: (key, result) => <span key={key}>
                             <a target="_blank" href={`${result[1]}://${result[2]}.${result[3]}${result[4]}`}>{result[2]}.{result[3]}{result[4]}</a>{result[5]}
                         </span>
}, {
    regex: /(\S+)\.([a-z]{2,}?)(.*?)( |\,|$|\.)/gim,
    fn: (key, result) => <span key={key}>
                             <a target="_blank" href={`http://${result[1]}.${result[2]}${result[3]}`}>{result[1]}.{result[2]}{result[3]}</a>{result[4]}
                         </span>
}];

let stringWithLinks = "Watch this on youtube.com";
let processed = processString(config)(stringWithLinks);

return (
    <div>Hello world! {processed}</div>
);

That will replace all links with or without "http://" protocol. If you want to replace only links with protocol, remove the second object from config array.

like image 6
Efog Avatar answered Nov 14 '22 21:11

Efog


First add <a> tag to string:

function httpHtml(content) {
  const reg = /(http:\/\/|https:\/\/)((\w|=|\?|\.|\/|&|-)+)/g;
  return content.replace(reg, "<a href='$1$2'>$1$2</a>");
}

console.log(httpHtml('hello http://google.com world'))
// => hello <a href="http://google.com">http://google.com</a> world

Then render string as html in react:

function MyComponent() {
  return <div dangerouslySetInnerHTML={{
    __html: httpHtml('hello http://google.com world')
  }} />;
}
like image 3
nodejh Avatar answered Nov 14 '22 20:11

nodejh


I wrote a short function to do it:

const RE_URL = /\w+:\/\/\S+/g;

function linkify(str) {
  let match;
  const results = [];
  let lastIndex = 0;
  while (match = RE_URL.exec(str)) {
    const link = match[0];
    if (lastIndex !== match.index) {
      const text = str.substring(lastIndex, match.index);
      results.push(
        <span key={results.length}>{text}</span>,
      );
    }
    results.push(
      <a key={results.length} href={link} target="_blank">{link}</a>
    );
    lastIndex = match.index + link.length;
  }
  if (results.length === 0) {
    return str;
  }
  if (lastIndex !== str.length) {
    results.push(
      <span key={results.length}>{str.substring(lastIndex)}</span>,
    );
  }
  return results;
}
like image 2
Aram Kocharyan Avatar answered Nov 14 '22 20:11

Aram Kocharyan