Read More

Disclosure

Text with expandable truncated content.

Preview

Usage

example.jsx
import { ReadMore } from "@/components/ui/read-more";

export default function Example() {
  return <ReadMore />;
}

Source Code

Copy this file into components/ui/read-more.jsx in your project.

read-more.jsx
"use client";

import { forwardRef, useState } from "react";
import { cn } from "@/lib/utils";

const ReadMore = forwardRef(({ className, text = "", maxLength = 150, moreLabel = "Read more", lessLabel = "Read less", ...props }, ref) => {
  const [expanded, setExpanded] = useState(false);
  const shouldTruncate = text.length > maxLength;

  return (
    <div ref={ref} className={cn("text-sm", className)} {...props}>
      <span>{expanded || !shouldTruncate ? text : `${text.slice(0, maxLength)}…`}</span>
      {shouldTruncate && (
        <button onClick={() => setExpanded(!expanded)} className="ml-1 font-medium text-primary hover:underline">
          {expanded ? lessLabel : moreLabel}
        </button>
      )}
    </div>
  );
});
ReadMore.displayName = "ReadMore";

export { ReadMore };

Quick Install

Make sure you have the cn() utility set up. It requires clsx and tailwind-merge.

npm install clsx tailwind-merge