npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@lg-chat/message

v11.0.1

Published

lg-chat Message

Readme

Message

Installation

PNPM

pnpm add @lg-chat/message

Yarn

yarn add @lg-chat/message

NPM

npm install @lg-chat/message

Example

import { Message } from '@lg-chat/message';

return (
  <div>
    <Message messageBody="Question" />
    <Message isSender={false} messageBody="Answer" />
  </div>
);

Compound Components

The Message component uses a compound component pattern, allowing you to compose different parts of a message using subcomponents like Message.Actions, Message.Links, Message.Promotion, Message.ActionCard, and Message.VerifiedBanner.

Note: The layout and order of compound components are enforced by the Message component itself. Even if you change the order of subcomponents in your JSX, they will be rendered in the correct, intended order within the message bubble. This ensures consistent UI and accessibility regardless of how you compose your message children.

Message.Actions

import React from 'react';
import { Message } from '@lg-chat/message';
import { MessageRatingValue } from '@lg-chat/message-rating';

const MessageWithActions = () => {
  const handleCopy = () => console.log('Message copied');
  const handleRetry = () => console.log('Message retried');

  const handleRatingChange = (
    e: React.ChangeEvent<HTMLInputElement>,
    options: { rating: MessageRatingValue },
  ) => {
    console.log('Rating changed:', options.rating);
  };

  const handleSubmitFeedback = async (
    e: React.FormEvent<HTMLFormElement>,
    options: { rating: MessageRatingValue; feedback?: string },
  ) => {
    console.log('Feedback submitted:', options);
  };

  return (
    <Message messageBody="Test message">
      <Message.Actions
        onClickCopy={handleCopy}
        onClickRetry={handleRetry}
        onRatingChange={handleRatingChange}
        onSubmitFeedback={handleSubmitFeedback}
      />
    </Message>
  );
};

Message.Links

import React from 'react';
import { Message } from '@lg-chat/message';

const MessageWithLinks = () => {
  const links = [
    {
      href: 'https://mongodb.design',
      children: 'LeafyGreen UI',
      variant: 'Website',
    },
    {
      href: 'https://mongodb.github.io/leafygreen-ui/?path=/docs/overview-introduction--docs',
      children: 'LeafyGreen UI Docs',
      variant: 'Docs',
    },
    {
      href: 'https://learn.mongodb.com/',
      children: 'MongoDB University',
      variant: 'Learn',
    },
  ];

  const handleLinkClick = () => console.log('Link clicked');

  return (
    <Message isSender={false} messageBody="Test message">
      <Message.Links
        links={links}
        onLinkClick={handleLinkClick}
        headingText="Related Resources"
      />
    </Message>
  );
};

Message.Promotion

import React from 'react';
import { Message } from '@lg-chat/message';

const MessageWithPromotion = () => {
  const handlePromotionClick = () => console.log('Promotion clicked');

  return (
    <Message isSender={false} messageBody="Test message">
      <Message.Promotion
        promotionText="Go learn more about this skill!"
        promotionUrl="https://learn.mongodb.com/skills"
        onPromotionLinkClick={handlePromotionClick}
      />
    </Message>
  );
};

Message.ActionCard

import React from 'react';
import { Message, ActionCardState } from '@lg-chat/message';
import DatabaseIcon from '@leafygreen-ui/icon/dist/Database';

const MessageWithActionCard = () => {
  const handleCancel = () => console.log('Cancel clicked');
  const handleRun = () => console.log('Run clicked');
  const handleToggleExpanded = (isOpen: boolean) => {
    console.log('Expanded state:', isOpen);
  };

  return (
    <Message isSender={false} messageBody="Test message">
      <Message.ActionCard
        chips={[{ label: 'MongoDB', glyph: <DatabaseIcon /> }]}
        initialIsExpanded={false}
        onToggleExpanded={handleToggleExpanded}
        showExpandButton={true}
        state={ActionCardState.Idle}
        title="Run list-databases?"
      >
        <Message.ActionCard.ExpandableContent>
          {`# Tool Execution Result

This is a markdown content example showing tool execution results.

\`\`\`javascript
const result = await tool.execute();
console.log(result);
\`\`\``}
        </Message.ActionCard.ExpandableContent>
        <Message.ActionCard.Button onClick={handleCancel}>
          Cancel
        </Message.ActionCard.Button>
        <Message.ActionCard.Button onClick={handleRun} variant="primary">
          Run
        </Message.ActionCard.Button>
      </Message.ActionCard>
    </Message>
  );
};

Message.VerifiedBanner

import React from 'react';
import { Message } from '@lg-chat/message';

const MessageWithVerifiedBanner = () => {
  return (
    <Message isSender={false} messageBody="Test message">
      <Message.VerifiedBanner
        verifier="MongoDB Staff"
        verifiedAt={new Date('2024-03-24T16:20:00Z')}
        learnMoreUrl="https://mongodb.com/docs"
      />
    </Message>
  );
};

Complete Example with All Subcomponents

import React from 'react';
import { Message, ActionCardState } from '@lg-chat/message';
import { MessageRatingValue } from '@lg-chat/message-rating';

const Example = () => {
  const handleCopy = () => console.log('Message copied');
  const handleRetry = () => console.log('Message retried');

  const handleRatingChange = (
    e: React.ChangeEvent<HTMLInputElement>,
    options: { rating: MessageRatingValue },
  ) => {
    console.log('Rating changed:', options.rating);
  };

  const handleSubmitFeedback = async (
    e: React.FormEvent<HTMLFormElement>,
    options: { rating: MessageRatingValue; feedback?: string },
  ) => {
    console.log('Feedback submitted:', options);
  };

  const links = [
    {
      href: 'https://mongodb.design',
      children: 'LeafyGreen UI',
      variant: 'Website',
    },
    {
      href: 'https://mongodb.com/docs',
      children: 'MongoDB Docs',
      variant: 'Docs',
    },
  ];

  const handleLinkClick = () => console.log('Link clicked');
  const handlePromotionClick = () => console.log('Promotion clicked');

  const handleCancel = () => console.log('Cancel clicked');
  const handleRun = () => console.log('Run clicked');

  return (
    <Message isSender={false} messageBody="Test message">
      <Message.ActionCard
        title="Run list-databases?"
        state={ActionCardState.Idle}
      >
        <Message.ActionCard.ExpandableContent>
          {`# Tool Execution Result

This is a markdown content example showing tool execution results.`}
        </Message.ActionCard.ExpandableContent>
        <Message.ActionCard.Button onClick={handleCancel}>
          Cancel
        </Message.ActionCard.Button>
        <Message.ActionCard.Button onClick={handleRun} variant="primary">
          Run
        </Message.ActionCard.Button>
      </Message.ActionCard>
      <Message.Promotion
        promotionText="Go learn more about this skill!"
        promotionUrl="https://learn.mongodb.com/skills"
        onPromotionLinkClick={handlePromotionClick}
      />
      <Message.Actions
        onClickCopy={handleCopy}
        onClickRetry={handleRetry}
        onRatingChange={handleRatingChange}
        onSubmitFeedback={handleSubmitFeedback}
      />
      <Message.VerifiedBanner
        verifier="MongoDB Staff"
        verifiedAt={new Date('2024-03-24T16:20:00Z')}
        learnMoreUrl="https://mongodb.com/docs"
      />
      <Message.Links links={links} onLinkClick={handleLinkClick} />
    </Message>
  );
};

Properties

Message

| Prop | Type | Description | Default | | --------------- | --------------------------------------------------------------------------------------------------- | --------------------------------------------------- | ------- | | isSender | boolean | Indicates if the message is from the current user | true | | markdownProps | LGMarkdownProps | Props passed to the internal ReactMarkdown instance | | | messageBody | string | Message body text passed to LGMarkdown | | | sourceType | 'markdown' \| 'text' | Determines the rendering method of the message | | | ... | HTMLElementProps<'div'> | Props spread on the root element | |

Message.Actions

| Prop | Type | Description | Default | | ------------------------------- | ----------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | | errorMessage (optional) | ReactNode | Optional error message to display when feedback submission fails. | 'Oops, please try again.' | | onClickCopy (optional) | MouseEventHandler<HTMLButtonElement> | Callback fired when the copy button is clicked. | | | onClickRetry (optional) | MouseEventHandler<HTMLButtonElement> | Callback fired when the retry button is clicked. If not provided, the retry button will not be rendered | | | onCloseFeedback (optional) | MouseEventHandler<HTMLButtonElement> | Callback fired when the feedback form is closed by clicking the close button | | | onRatingChange (optional) | (e: ChangeEvent<HTMLInputElement>, options: { rating: MessageRatingValue }) => void | Callback fired when the user clicks the like or dislike button. Receives the original change event and an options object with the rating. If not provided, the rating buttons will not be rendered | | | onSubmitFeedback (optional) | (e: FormEvent<HTMLFormElement>, options: { rating: MessageRatingValue; feedback?: string }) => void | Callback when the user submits the feedback form. Receives the original form event, plus an options object with rating and feedback. If not provided, the feedback form will not be rendered | | | submitButtonText (optional) | string | Optional text for the feedback form's submit button | 'Submit' | | submittedMessage (optional) | ReactNode | Optional success message to display after feedback is submitted. | 'Thanks for your feedback!' |

Message.Links

| Prop | Type | Description | Default | | -------------------------- | -------------------------------- | ------------------------------------------------------------ | --------------------- | | headingText (optional) | string | The text to display as the heading of the links section. | 'Related Resources' | | links | Array<RichLinkProps> | An array of link data to render in the links section. | | | onLinkClick (optional) | ({ children: string }) => void | A callback function that is called when any link is clicked. | | | ... | HTMLElementProps<'div'> | Props spread on the root element | |

Message.Promotion

| Prop | Type | Description | Default | | ----------------------------------- | ------------------------- | ---------------------------------------- | ------- | | promotionText | string | Promotion text content. | | | promotionUrl | string | Promotion URL for the "Learn More" link. | | | onPromotionLinkClick (optional) | () => void | Promotion onClick callback handler. | | | ... | HTMLElementProps<'div'> | Props spread on the root element | |

Message.ActionCard

| Prop | Type | Description | Default | | -------------------------------- | ------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | | chips (optional) | Array<{ label: ReactNode; glyph?: ReactNode; formatTooltip?: (label: ReactNode) => ReactNode }> | Metadata chips displayed in the header. Each chip supports label, optional glyph icon, and optional formatTooltip function to customize tooltip content. Tooltips are always shown on hover for chips in ActionCard. | [] | | darkMode (optional) | boolean | Determines if the component will render in dark mode | false | | description (optional) | ReactNode | Optional description text displayed below the title row in the Header. | | | initialIsExpanded (optional) | boolean | Initial state of the expandable section. Ignored when showExpandButton is false. | false | | onToggleExpanded (optional) | (isOpen: boolean) => void | Callback fired when the expansion toggle is clicked. Receives the new open state as a parameter. | | | showExpandButton (optional) | boolean | Whether the toggle button is visible. | true | | state | 'idle' \| 'running' \| 'success' \| 'error' \| 'canceled' | The current lifecycle state of the interaction. Can use string literals or import ActionCardState enum from @lg-chat/message. | | | title | ReactNode | Primary label displayed in the Header. | | | ... | HTMLElementProps<'div'> | Props spread on the container div element | |

Message.ActionCard.Button

Message.ActionCard.Button accepts all props from @leafygreen-ui/button, except for the size prop which cannot be configured and is always set to 'small'.

Message.ActionCard.ExpandableContent

| Prop | Type | Description | Default | | ---------- | ------------------------- | ---------------------------------------------------------------------------- | ------- | | children | string | Markdown content to render in the expandable content area. Must be a string. | | | ... | HTMLElementProps<'div'> | Props spread on the container div element | |

Message.VerifiedBanner

| Prop | Type | Description | Default | | --------------------------- | -------- | ------------------------------------------------- | ------- | | learnMoreUrl (optional) | string | URL to learn more about the verification. | | | verifiedAt (optional) | Date | The time the message was last verified. | | | verifier (optional) | string | The name of the entity that verified the message. | |

Behavior

Message.Actions

The Message.Actions component provides a comprehensive set of actions for chat messages.

Rendering Behavior

  • If only some optional props are provided, only those corresponding buttons/functionality are rendered:
    • Copy Button: Always renders
    • Retry Button: Renders when onClickRetry is provided
    • Rating Buttons: Render when onRatingChange is provided
    • Feedback Form: Shows when a rating is selected and onSubmitFeedback is provided

Context Integration

The component relies on MessageContext to access the message body for copy functionality.

Rating and Feedback Flow

  1. Rating Only: User clicks thumbs up or thumbs down (only visible when onRatingChange is provided)

    • Calls onRatingChange with the selected rating
    • No feedback form appears
  2. Rating + Feedback: User clicks thumbs up or thumbs down, then feedback form appears

    • Calls onRatingChange with the selected rating
    • Feedback form appears with a textarea for additional comments
    • User can optionally provide feedback text
    • User clicks submit to send feedback
    • Form shows success message and calls onSubmitFeedback with rating and feedback

State Management

The component manages its own internal state for:

  • Message rating: 'unselected' | 'disliked' | 'liked'
  • Feedback text input
  • Form state: 'unset' | 'submitting' | 'submitted' | 'error'

Form state is reset when the feedback form is closed or when a new rating is selected.

Message.Links

The Message.Links component provides an expandable/collapsible section for displaying related links.

Rendering Behavior

  • If the links array is empty, the component returns null and does not render anything
  • Links are displayed in an expandable section with a chevron toggle button
  • The section starts collapsed by default and can be expanded to show all links
  • The link objects provided to the Message.Links component's links prop can leverage the following variant values which map to pre-defined badge glyphs, labels, and colors.
    • "Blog"
    • "Book"
    • "Code"
    • "Docs"
    • "Learn"
    • "Video"
    • "Website"

State Management

The component manages its own internal state for:

  • Expansion state: Controls whether the links section is expanded or collapsed

Message.Promotion

The Message.Promotion component displays promotional content with an award icon and "Learn More" link.

Message.ActionCard

The Message.ActionCard component displays actionable, stateful cards with expandable content and buttons.

Rendering Behavior

  • Buttons only render when state="idle"
  • Multiple Message.ActionCard.Button components can be used to render buttons

State Management

The component manages its own internal state for:

  • Expansion state: Controls whether the expandable content section is expanded or collapsed
  • The expansion state can be configured via initialIsExpanded and onToggleExpanded props

Message.VerifiedBanner

The Message.VerifiedBanner component displays verification information for messages.

Rendering Behavior

  • If no verification props (verifier, verifiedAt, learnMoreUrl) are provided, basic "Verified" text is displayed
  • The banner automatically formats the verification date using toLocaleDateString()
  • "Learn More" link is displayed when optional learnMoreUrl is provided