shadimage
lens-blocks
componentlens-markdownsource: ok · hit

Lens Markdown

A Markdown renderer for Lens posts and comments, supporting mentions, links, and rich text formatting.

npx shadcn add "https://lensblocks.com/r/lens-markdown.json"
free

Where it goes

comment

Use cases

community

Tags auto-generated by rules on 9/24/2026 — empty means no evidence, not lack of support.

Dependencies

Bundle weight · light
@lens-protocol/react@0.0.0-canary-20250820102520@lens-protocol/metadata@2.1.0react-markdown@9.0.3remark-gfm@4.0.1remark-breaks@4.0.0remark-linkify-regex@1.2.1strip-markdown@6.0.0

Registry dependencies

https://lensblocks.com/r/utils.json

Files4 · source cached 10/14/2026, 2:06:37 PM

registry/new-york/components/common/lens-markdown.tsx
// @ts-ignore
import linkifyRegex from "remark-linkify-regex";
import stripMarkdown from "strip-markdown";
import remarkGfm from "remark-gfm";
import remarkBreaks from "remark-breaks";
import { RegEx } from "@/registry/new-york/lib/regex";
import ReactMarkdown, { Components } from "react-markdown";
import { cn } from "@/lib/utils";
import { LensMentionLink } from "@/registry/new-york/components/common/lens-mention-link";
import { AccountMention, GroupMention } from "@lens-protocol/react";
import { LensTagLink } from "@/registry/new-york/components/common/lens-tag-link";
import { truncateUrl } from "@/registry/new-york/lib/lens-utils";

type Props = {
  content: string;
  className?: string;
  mentions?: (AccountMention | GroupMention)[];
};

export const LensMarkdown = (props: Props) => {
  const { content, className, mentions } = props;
  const remarkPlugins = [
    [
      stripMarkdown,
      {
        keep: ["blockquote", "code", "delete", "emphasis", "inlineCode", "link", "list", "listItem", "strong"],
      },
    ],
    remarkGfm,
    remarkBreaks,
    linkifyRegex(RegEx.URL),
    linkifyRegex(RegEx.MENTION),
    linkifyRegex(RegEx.HASHTAG),
    linkifyRegex(RegEx.CASHTAG),
  ];

  const components: Components = {
    // linkifyRegex will find mentions, hashtags, and cashtags, and replace them with a link
    // here we are defining how to render that link
    a: (props: any) => {
      const mention = mentions?.find(mention => mention.replace.from === props.title);

      if (mention) {
        return <LensMentionLink mention={mention} />;
      }

      if (props.title?.startsWith("#") || props.title?.startsWith("$")) {
        return <LensTagLink tag={props.title} />;
      }

      return (
        <a {...props} target="_blank" rel="noopener noreferrer" className="font-bold hover:underline">
          {truncateUrl(props.href)}
        </a>
      );
    },
  };
  return (
    <ReactMarkdown
      remarkPlugins={remarkPlugins}
      components={components}
      className={cn("break-words hyphens-none line-clamp-6 whitespace-pre-wrap", className)}
    >
      {content}
    </ReactMarkdown>
  );
};
registry/new-york/components/common/lens-mention-link.tsx
import { ComponentProps } from "react";
import { AccountMention, GroupMention } from "@lens-protocol/react";
import { getUsernamePath } from "@/registry/new-york/lib/lens-utils";

type Props = {
  mention: AccountMention | GroupMention;
  href?: string;
};

type LinkProps = Omit<ComponentProps<"a">, "href">;

export const LensMentionLink = (props: Props & LinkProps) => {
  if (props.mention.__typename === "GroupMention") {
    const href = props.href ?? `/g/${props.mention.replace.from.replace("#", "")}`;
    return (
      <a {...props} href={href}>
        {props.mention.replace.to}
      </a>
    );
  }

  const namespace = props.mention.namespace;
  const href = props.href ?? getUsernamePath(props.mention.replace.to, namespace);
  return (
    <a {...props} href={href}>
      {props.mention.replace.to.replace("@lens/", "@")}
    </a>
  );
};
registry/new-york/components/common/lens-tag-link.tsx
import { ComponentProps } from "react";

type Props = {
  tag: string;
  href?: string;
};

type LinkProps = Omit<ComponentProps<"a">, "href">;

export const LensTagLink = (props: Props & LinkProps) =>
  props.href ? (
    <a {...props} href={props.href}>
      {props.tag}
    </a>
  ) : (
    <span className="font-bold">{props.tag}</span>
  );
registry/new-york/lib/regex.ts
const regexLookbehindAvailable: boolean = ((): boolean => {
  try {
    return "ab".replace(/(?<=a)b/g, "c") === "ac";
  } catch {
    return false;
  }
})();

const MATCH_BEHIND = regexLookbehindAvailable ? "(?<=^|\\s)" : "";

const MENTION_NAMESPACE = "\\w+\\/";
const MENTION_BODY = "([\\dA-Za-z]\\w{2,25})";

export const RegEx = {
  CASHTAG: /(\$\w*[A-Za-z]\w*)/g,
  HASHTAG: /(#\w*[A-Za-z]\w*)/g,
  MENTION: new RegExp(`${MATCH_BEHIND}@${MENTION_NAMESPACE}${MENTION_BODY}`, "g"),
  URL: /\b(http|https):\/\/([\p{L}\p{N}_-]+(?:(?:\.[\p{L}\p{N}_-]+)+))([\p{L}\p{N}_.,@?^=%&:\/~+#-]*[\p{L}\p{N}_@?^=%&\/~+#-])/gu,
};

More from lens-blocks

Browse all components in this library →