/^/
MediumText Processing5 min read

Markdown Link Regex

Matches Markdown link syntax [text](url) and captures the link text and destination, with optional support for a quoted title.

#markdown#links#text-processing#parsing#documentation

Regex Pattern

\[([^\]]+)\]\(([^)\s]+)(?:\s+"[^"]*")?\)

Pattern Breakdown

Hover over a token to see what it does.

\[([^\]]+)\]\(([^)\s]+)(?:\s+"[^"]*")?\)
TokenMeaning
\[Literal opening square bracket that starts the link text
([^\]]+)Capture group 1: the link text, one or more characters that are not ]
\]Literal closing square bracket ending the link text
\(Literal opening parenthesis that starts the destination
([^)\s]+)Capture group 2: the URL, one or more characters that are not ) or whitespace
(?:\s+"[^"]*")?Optional non-capturing group for a space-separated quoted title, e.g. "Example"
\)Literal closing parenthesis ending the link

Detailed Explanation

What it does

This pattern locates inline Markdown links of the form [link text](https://example.com) anywhere in a string and captures the visible text and the target URL as separate groups. It also tolerates an optional title attribute in quotes after the URL, as in [text](url "Title").

Why it works

The two bracket-delimited groups use negated character classes ([^\]]+ and [^)\s]+) instead of greedy wildcards so each group stops precisely at its own closing delimiter without overrunning into the rest of the link or accidentally spanning multiple links. The optional non-capturing group for the title is anchored to whitespace followed by a quoted string, so it only engages when a title is actually present.

Common use cases

  • Extracting all links and their labels from a Markdown document for a table of contents
  • Rewriting relative links to absolute links during a static site build
  • Validating that documentation contains no malformed or empty link syntax
  • Converting Markdown links to HTML anchor tags in a lightweight renderer

Edge cases

  • Image syntax like ![alt](image.png) still matches the trailing [alt](image.png) portion since the pattern is unanchored and doesn't check for a preceding !
  • Links with a title attribute, e.g. [text](url "Title"), are matched including the title in the full match but the title itself isn't captured separately
  • Empty link text such as [] () fails to match because the text group requires at least one non-] character
  • URLs containing spaces are not matched because the destination group stops at the first whitespace character
  • Nested brackets inside the link text, like [a [b] c](url), will stop capturing at the first ]

Limitations

  • Does not validate that the captured URL is itself well-formed; use a dedicated URL pattern for that
  • Reference-style links like [text][ref] are not matched, only inline links
  • Does not distinguish between a real link and an image link prefixed with !
  • Titles using single quotes instead of double quotes are not recognized

Interactive Tester

Edit the pattern or text below — matching runs live in your browser.

[GitHub](https://github.com) Check out [our docs](https://example.com/docs) for more. [Relative link](/about)
3 matches· capture groups: 2

Test Cases

Editable — add your own inputs to see if they pass.

InputExpectedResult
Pass
Pass
Pass
Pass
Pass
Pass
Pass
Pass
Pass

Language Variants

Production-ready examples in 12 languages.

const mdLinkRegex = /\[([^\]]+)\]\(([^)\s]+)(?:\s+"[^"]*")?\)/g;
const matches = [..."[Docs](https://example.com)".matchAll(mdLinkRegex)];
console.log(matches[0][1], matches[0][2]); // 'Docs' 'https://example.com'

Common Mistakes

Using .* instead of [^\]]+ for the link text, causing the match to greedily span across multiple links on the same line

Fix: Use a negated character class scoped to the delimiter (e.g. [^\]]+) so each group stops at its own closing bracket

Forgetting the g flag when extracting all links from a document, so only the first link is found

Fix: Add the g flag (or use matchAll/finditer/scan depending on language) to retrieve every match

Assuming this pattern also matches image syntax ![alt](src) as a distinct type

Fix: Check for a preceding ! character separately if images need to be excluded or handled differently

Performance Notes

  • The negated character classes [^\]]+ and [^)\s]+ are efficient because they can only match up to their terminating delimiter, avoiding backtracking blowups
  • Running this pattern with the global flag over a large document is linear in the length of the text
  • The optional title group only adds overhead when whitespace immediately follows the URL, so plain links are matched with minimal extra work

Browser Compatibility

EngineSupportedNotes
ChromeYes
FirefoxYes
SafariYes
EdgeYes
Node.jsYes