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

@opengov/mention-component

v0.1.3

Published

React component library for user mentions with typeahead search, permission validation, and notification integration

Maintainers

ashishsharma0101ashishsharma0101riddhi0711riddhi0711og-rdaveog-rdavejeremiahrhalljeremiahrhallmanishpatidar01manishpatidar01opengov_devopengov_devgravitypersistsgravitypersistsdarshan2836darshan2836hirenopengovhirenopengovgfroesoggfroesogvpatel-ogvpatel-ognand.jhanand.jhamgibsonmgibsonbhenizebhenizessinghal1906ssinghal1906jhounpmjhounpmarahman-ogarahman-ogankitsharmagabankitsharmagabkchenna-engkchenna-engshailesh-ogshailesh-ogsammiwei9119sammiwei9119jacobcdjacobcdprateek.sharmaprateek.sharmajavierrivasjavierrivaslawrenceatamlawrenceatamjwagner-ogjwagner-ogdannbohndannbohnmaheshma-opengovmaheshma-opengovbsuryawanshi1bsuryawanshi1jmo-opengovjmo-opengovpankajopengovpankajopengovamit_kulkarniamit_kulkarnipshreyash11pshreyash11gguptaopengovgguptaopengovakshadapatilakshadapatilppathakopengovppathakopengovpkhairnarpkhairnarogind-amehtaogind-amehtadallasdeveloperjimdallasdeveloperjimpriyadarshnirosypriyadarshnirosygrevankargrevankarkredkarkredkarpkawareopengovpkawareopengovdhanashri-joshidhanashri-joshivvndnvvndnshantanuk90shantanuk90zs441989zs441989thamptonthamptonjkirchhofjkirchhofvneznakhinvneznakhinashutoshopengovashutoshopengovmazcuetamazcuetaruthraruthraalokkumaropengovalokkumaropengovsarangwagh77sarangwagh77amdv-ogamdv-ogdlutgerdlutgernoelparisinoelparisidkrainesdkrainesbfelacobfelacofwachsfwachssatyajit987satyajit987tozaisentozaisenrshinde21rshinde21yueluyueluogisiddogisiddjohnconleyognpmjohnconleyognpmmattbangertmattbangertssulssulokotkevychokotkevychsunnybsunnybshreyaguptashreyaguptavinaybongalevinaybongalejoshuadotsonjoshuadotsonmhelgersonmhelgersonlcoffee-johnsonlcoffee-johnsonmmagni-opengovmmagni-opengovkk-ogkk-ogmtopallimtopallimsorokovskyimsorokovskyikgautam311kgautam311rboyle21rboyle21apatel2024apatel2024tapendra-ogtapendra-oggdemesagdemesaogjkochogjkochjkoppelogjkoppelogmprykhodkomprykhodkorfbagang17rfbagang17amagnusonamagnusonlcfitzglcfitzgog-naterolingog-naterolingameykhojeogameykhojeogvtannavtannabwilliams1981bwilliams1981jreandojreandobahlrichsbahlrichsshubhansshubhanskaditani-ogindiakaditani-ogindiamdempewolfmdempewolfnborkarnborkaraamartinezaamartinezkiliancsogkiliancsogchaoranhuangopengovchaoranhuangopengovbramosopengovbramosopengovmgruhlopengovmgruhlopengovogind-smoreogind-smorebsand_ogbsand_oggaryalgaryaljdelledonne-opengovjdelledonne-opengovstzphenstzphenanroutanroutog-ericlutleyog-ericlutleypranitkhadilkaropengovpranitkhadilkaropengovhstockshstockswglasbrennerwglasbrennersnagpalsnagpalmaxpeng-opengovmaxpeng-opengovdkolomiietsdkolomiietsjsivitsjsivitsecschottecschottvenkateshanavekarvenkateshanavekarharshalbhaveharshalbhavealinderalindercmarkegardogcmarkegardogmnetk3mnetk3trothfeldtrothfeldamalakar4amalakar4erikwilliamserikwilliamsahobartopengovahobartopengovpooja.guptapooja.guptamkelkarmkelkarabgupta01abgupta01zacharyuanzacharyuanbsangalebsangalesdeshpande-ogsdeshpande-ogvanavekarvanavekarross-opengovross-opengovcdeshpande-ogcdeshpande-ogsubhenduroysubhenduroyrkirtane-opengovrkirtane-opengovjguo144jguo144rparetkarrparetkarankur.singhalankur.singhalsaurabh_nimsesaurabh_nimsesadkingbillysadkingbillyvinayak-motevinayak-motepmadurpmadurkshah2026kshah2026wporter-opengovwporter-opengovkevinyoukevinyouashishkumarogashishkumarogherbwarrenherbwarrenkboyko_ogkboyko_ogchetan-xoriantchetan-xoriantvmerino04vmerino04sjadhav-ogsjadhav-ogawaknisawaknisypusaneypusaneogi-shubhamkogi-shubhamkkisshoregunasekarankisshoregunasekarangabyvlcgabyvlcaudreyjaudreyjog-apatoleog-apatolemanmohanopengovmanmohanopengovalinabasiukalinabasiuksmhamane-opengovsmhamane-opengovemarin3425emarin3425prathamesh-koliprathamesh-kolinanaynaominanaynaomiokalmurzayevokalmurzayevshantanu2918shantanu2918floppyears_opengovfloppyears_opengovprafulpatilprafulpatildraghuvanshidraghuvanshivikassharma-ogvikassharma-ogctiwari-ogctiwari-ogsumedhc-opengovsumedhc-opengovkirkwonkirkwonrbtingle78rbtingle78eclarkeclarkjmartens-opengovjmartens-opengovkthorat-opengovkthorat-opengovparmarpritishparmarpritishsiddharthkalesiddharthkalerevans20revans20og-ashahog-ashahaherrera-groppaherrera-groppshikexue2shikexue2koletokoletoparmeshwar-itparmeshwar-itjesusescjesusescvickyjungharevickyjunghareankur_shrivastavankur_shrivastavogngogngsusanzeaogsusanzeaogsavasaralaogsavasaralaogabarbariaabarbariadhananjaykanungodhananjaykanungodhiraj-bhalerao-npmdhiraj-bhalerao-npmservices-npm-user-readservices-npm-user-readsnikam-ogsnikam-ogvvaishnavvvaishnavdhariharandhariharanogvkarumanchi-npmogvkarumanchi-npmnchaudharinchaudhariamit4767amit4767wli11wli11rpatharkarrpatharkarchill-orgchill-orgzwilliams-opengovzwilliams-opengovarnavg311arnavg311kevinkelchen_ogkevinkelchen_ogogi-prakashpandeyogi-prakashpandeyatharvashewaleatharvashewaletderosatderosafanyitangfanyitangaditipatiladitipatilajanefalkarajanefalkarsurabhishroffsurabhishroffasargarasargarjonlaijonlairobert-opengovrobert-opengovrudreshogrudreshoggabriel-rodr-opengovgabriel-rodr-opengovnbairwalnbairwalsandesh.deshmanesandesh.deshmanespbala95spbala95akshaydesaiogakshaydesaiogpjain0072pjain0072abhombe1564abhombe1564ajinkyaopengovajinkyaopengovjonathanbraunjonathanbraunamitgandhinzamitgandhinzaseksenaaseksenajwyaunjwyauntanvibtanvibkjadhav_opengovkjadhav_opengovarykowski-ogarykowski-ogsmita_patil_ogsmita_patil_ogpooja31pooja31sathvikreddy1408sathvikreddy1408allisonkimdesignallisonkimdesignopengov_vishalopengov_vishalabule-opengovabule-opengovsethcummins660sethcummins660ratneshsahuogratneshsahuograhulkadu19rahulkadu19rbhiderbhidedhanashree1217dhanashree1217og-anilguptaog-anilguptabchegebchegesagunchauhansagunchauhanlfernandes-opengovlfernandes-opengovmoti-ogmoti-ogrbhortakkerbhortakke__lokesh____lokesh__abhi05abhi05rahulsingh1402rahulsingh1402asardesai1asardesai1a-hundekara-hundekarckim-opengovckim-opengovsanchitadesignersanchitadesigneraman_shuklaaman_shuklashailendrapshailendrapankurmuthaankurmutharobyy_opengovrobyy_opengovsusmit-kulkarnisusmit-kulkarniapajusiapajusipwhitneyogpwhitneyogjburgess_opengovjburgess_opengovspokale-npmspokale-npmjhurley24jhurley24sohailaziz035sohailaziz035dhodapkaramitdhodapkaramitanthonyreoanthonyreobghutugadebghutugadesmehta-opengovsmehta-opengovallanm-opengovallanm-opengovokirpane-gov-2okirpane-gov-2hdevasthalihdevasthaliprachetaschandratreyaprachetaschandratreyajsong7664jsong7664gvijaygvijaynav123dnav123ddtomar25dtomar25vaishnav_opengovvaishnav_opengovjwencljwenclkeyuritatukeyuritatuvedantlachakevedantlachaketejus-stejus-skanishkmahor-70kanishkmahor-70knillawarknillawardganesan11dganesan11gmulertgmulertshubhamkaleshubhamkalengoyal-opengovngoyal-opengovprasad713ogprasad713ogpjethwani-opengovpjethwani-opengovkmmarshkmmarshchaitanyapilkhanechaitanyapilkhanevprakash-opengovvprakash-opengovmkimopengovmkimopengovpdeshmukh-opengovpdeshmukh-opengoveng-bot-readereng-bot-readersbelapuresbelapureabhidabhidcgirouardcgirouardogind-rdesaiogind-rdesaiaksjoshi_opengovaksjoshi_opengovrjoshi-opengovrjoshi-opengovsayed_shahsayed_shahanilbhanushali_oganilbhanushali_ogaachouguleaachouguleaparalikaraparalikarabhijeetkumar-npmabhijeetkumar-npmnolanpruettnolanpruettnavyakatiyarnavyakatiyarayushopengovayushopengovgmekala1975gmekala1975basantksrbasantksrshubham_sahu_sasshubham_sahu_sasrtambat-opengovrtambat-opengovgopi.gandhi.opengovgopi.gandhi.opengovsanketmagarsanketmagarlkumbhakarlkumbhakarosabaneosabaneogind-ppathakogind-ppathakanmolssmanmolssmarkanmekonenarkanmekonenjnshawjnshawpshah1996pshah1996pritam123pritam123sourabhkarmarkar-opengovsourabhkarmarkar-opengovdev1450dev1450spokarnaspokarnabentleylongopengovbentleylongopengovsabhyatakiransabhyatakiranknambiknambivinayakjadonogvinayakjadonogkishore.kirdatkishore.kirdatsagarbamgudesagarbamgudefkhambatyfkhambatygovbarnesygovbarnesyprafullmanglaprafullmangladevdatt_gautamdevdatt_gautamniveditamagadumniveditamagadumdvijayakumarogdvijayakumarogachouhanopengovachouhanopengovcmannurucmannuruniteshguptaniteshguptadevangk1025devangk1025dvora15dvora15hkim-opengovhkim-opengovbentonyetmanbentonyetmanjarmstrong-ogjarmstrong-ogajaved_ogajaved_ogjhe02184jhe02184umishraumishramauogmauog

Readme

@opengov/mention-component

Shared React component library for user mention functionality across OpenGov products. Provides a rich text input with @-mention typeahead, user hover cards, permission warnings, and mention chips.

Installation

bun add @opengov/mention-component

Peer Dependencies

| Package | Version | | ---------------------------- | ------- | | @mui/material | ^6.0.0 | | @opengov/capital-mui-theme | * | | react | ^19.0.0 | | react-dom | ^19.0.0 |

Quick Start

Wrap your app (or subtree) with MentionProvider, then drop in MentionInputConfigurable:

import { MentionProvider, MentionInputConfigurable } from '@opengov/mention-component';

function CommentSection() {
  return (
    <MentionProvider
      baseUrl="/api/user-mention-service/v1"
      getAccessToken={() => auth0.getAccessTokenSilently()}
    >
      <MentionInputConfigurable
        entityId="entity-uuid"
        sourceProduct="cit"
        sourceRecordUrn="urn:opengov:cit:permit:12345"
        sourceContextType="comment"
        sourceContextId="comment-thread-1"
        deepLinkUrl="https://app.opengov.com/cit/permits/12345"
        placeholder="Add a comment... Type @ to mention someone"
        onMentionCreated={(mention) => console.log('Created:', mention)}
      />
    </MentionProvider>
  );
}

That's it for most use cases. The Configurable API handles typeahead, suggestion rendering, permission warnings, and mention creation out of the box.

Components

MentionProvider

Global context provider that supplies the API base URL, auth token getter, and (optionally) the tenant entityId to all mention components. When entityId is set, smart components like <MentionChip /> and <MentionHoverCard /> can self-fetch user details without any prop drilling.

<MentionProvider
  baseUrl="/api/user-mention-service/v1"
  getAccessToken={() => auth0.getAccessTokenSilently()}
  entityId="entity-uuid"
>
  {children}
</MentionProvider>

| Prop | Type | Required | Description | | ----------------- | ----------------------- | -------- | -------------------------------------------------------------------------------------------- | | baseUrl | string | Yes | Base URL of the user-mention-service API | | getAccessToken | () => Promise<string> | Yes | Async function that returns a valid bearer token | | entityId | string | No | Tenant UUID used by smart MentionChip / MentionHoverCard to self-fetch user details | | debounceMs | number | No | Typeahead debounce (default 150ms) | | minQueryLength | number | No | Minimum query length (fixed at 3 by AC API) | | currentUserName | string | No | Name of the current user; used in mention notifications |

MentionInputConfigurable

All-in-one mention input. Covers ~90% of use cases.

<MentionInputConfigurable
  entityId="entity-uuid"
  sourceProduct="cit"
  sourceRecordUrn="urn:opengov:cit:permit:12345"
  sourceContextType="comment"
  sourceContextId="comment-thread-1"
  deepLinkUrl="https://app.opengov.com/cit/permits/12345"
  placeholder="Type @ to mention..."
  onMentionCreated={(mention) => {
    /* ... */
  }}
  onMentionError={(error) => {
    /* ... */
  }}
/>

| Prop | Type | Required | Description | | ----------------------- | -------------------------------------- | -------- | ------------------------------------------------------ | | entityId | string | Yes | Entity UUID for the current tenant | | sourceProduct | SourceProduct | Yes | Product identifier (see types below) | | sourceRecordUrn | string | Yes | URN of the record being commented on | | sourceContextType | SourceContextType | Yes | Context type | | sourceContextId | string | Yes | Unique ID for the comment thread/context | | deepLinkUrl | string | Yes | URL included in the notification to the mentioned user | | placeholder | string | No | Input placeholder text | | disabled | boolean | No | Disable the input | | maxMentionsPerComment | number | No | Max mentions per submission (default: 20) | | sx | SxProps<Theme> | No | MUI sx styling overrides | | onMentionCreated | (mention: MentionResult) => void | No | Callback fired per successful mention | | onMentionError | (error: MentionApiErrorData) => void | No | Callback fired on error |

MentionInputComposable

For teams that need fine-grained control over layout and rendering (~10% of use cases). Uses compound component pattern with sub-components.

<MentionInputComposable
  entityId="entity-uuid"
  sourceProduct="financial"
  sourceRecordUrn="urn:opengov:financial:journal:999"
  sourceContextType="note"
  sourceContextId="note-1"
  deepLinkUrl="https://app.opengov.com/financial/journals/999"
>
  <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
    <MentionInputComposable.Editor placeholder="Write a note..." />
    <MentionInputComposable.PermissionWarning />
  </Box>
</MentionInputComposable>

Sub-components:

| Sub-component | Description | | ------------------------------------------ | ------------------------------------------------------------------- | | MentionInputComposable.Editor | The TipTap rich text editor. Props: placeholder, disabled, sx | | MentionInputComposable.Suggestions | Suggestion list (rendered automatically by TipTap) | | MentionInputComposable.PermissionWarning | Renders the permission warning when a user lacks record access |

MentionChip

Smart inline badge for displaying a mentioned user. Triggers a hover card on hover/focus.

When rendered inside a <MentionProvider entityId="…" />, the chip self-fetches the user's details (display name, role, department, avatar, deactivated status) from GET /:entityId/mentions/users/:userId — so callers only need to supply userId.

// Smart mode — pass only userId; details are fetched automatically
<MentionChip userId="user-uuid" />

// Presentational mode — pass details explicitly; nothing is fetched
<MentionChip
  userId="user-uuid"
  displayName="Jane Smith"
  role="Budget Analyst"
  department="Finance"
  permissionStatus="allowed"
  disableAutoFetch
/>

Any prop that's passed in takes precedence over fetched values, so callers that already have a display name (e.g. from a persisted mention record) see it instantly while the rest is filled in after hydration.

| Prop | Type | Required | Description | | ------------------ | -------------------------- | -------- | ------------------------------------------------------------------------- | | userId | string | Yes | User UUID | | displayName | string | No | Display name shown on the chip (falls back to fetched fullName) | | role | string | No | User's role (falls back to fetched value) | | department | string | No | User's department (falls back to fetched value) | | avatar | string \| null | No | Avatar URL (falls back to fetched value) | | isDeactivated | boolean | No | Show deactivated styling (falls back to fetched disabled flag) | | permissionStatus | PermissionStatus | No | Shows warning/blocked icon | | entityId | string | No | Tenant UUID override; falls back to <MentionProvider entityId="…" /> | | disableAutoFetch | boolean | No | When true, the chip renders only from props and makes no network calls | | onClick | (userId: string) => void | No | Click handler | | sx | SxProps<Theme> | No | MUI sx styling overrides |

MentionHoverCard

Smart popover card showing user details. Typically triggered by MentionChip but can be used standalone. Fetches user details lazily when opened (when inside a <MentionProvider />), unless disableAutoFetch is set.

// Standalone smart usage — the card fetches on first open
<MentionHoverCard
  userId="user-uuid"
  anchorEl={chipRef.current}
  open={isOpen}
  onClose={() => setIsOpen(false)}
/>

Same prop-vs-fetched precedence rules as MentionChip. Accepts the same entityId and disableAutoFetch props.

MentionSuggestionList

Typeahead dropdown for selecting users. Used internally by MentionInputConfigurable, but available for custom implementations.

<MentionSuggestionList
  items={users}
  isLoading={loading}
  error={null}
  selectedIndex={0}
  onSelect={(user) => handleSelect(user)}
  renderItem={(user, isSelected) => <CustomItem user={user} selected={isSelected} />}
/>

PermissionWarning

Inline alert shown when a mentioned user may not have access to the record.

<PermissionWarning
  userName="Jane Smith"
  onConfirm={() => proceedWithMention()}
  onCancel={() => cancelMention()}
/>

Hooks

useMentionTypeahead

Handles debounced user search with rate limiting.

const { items, isLoading, error, search, clear, isRateLimited } = useMentionTypeahead();

// Trigger search (200ms debounce, 1-char minimum)
search('jan', entityId, sourceRecordUrn);

useMentionApi

Handles mention creation requests.

const { createMention } = useMentionApi({
  onMentionCreated: (mention) => console.log(mention),
  onMentionError: (error) => console.error(error),
});

await createMention({
  sourceProduct: 'cit',
  sourceRecordUrn: 'urn:opengov:cit:permit:12345',
  sourceContextType: 'comment',
  sourceContextId: 'thread-1',
  mentions: [{ mentionedUserId: 'user-uuid' }],
  deepLinkUrl: 'https://app.opengov.com/cit/permits/12345',
});

useMentionContext

Access the MentionProvider context (baseUrl, getAccessToken, entityId).

useMentionUser

Resolve a single user's details by ID using the MentionProvider context. Backed by a shared module-level cache (5 min TTL) with in-flight request dedup, so N chips rendering the same user issue at most one network call.

const { user, isLoading, error } = useMentionUser('user-uuid');

Returns { user: null, isLoading: false } when no entityId is available (from either the argument or <MentionProvider />).

useMentionInputContext

Access the MentionInput context (mention count, pending warnings, callbacks). Must be used within a MentionInputConfigurable or MentionInputComposable.

Types

type SourceProduct = 'cit' | 'financial' | 'procurement' | 'eam' | 'budget' | 'reporting' | 'oth';
type SourceContextType = 'comment' | 'note' | 'workflow_thread';
type PermissionStatus = 'allowed' | 'warned' | 'blocked';

interface ResolvedUser {
  uuid: string;
  email: string;
  firstName: string;
  lastName: string;
  fullName: string;
  role: { name: string; displayName: string };
  department: string | null;
  avatar: string | null;
  hasRecordAccess?: boolean;
}

interface MentionResult {
  mentionId: string;
  mentionedUserId: string;
  permissionStatus: PermissionStatus;
  createdAt: string;
}

interface MentionApiErrorData {
  code: string;
  message: string;
  details?: Record<string, unknown>;
}

Storybook

Run Storybook locally to browse and interact with all components:

bun run storybook

Accessibility

All components target WCAG 2.1 AA compliance:

  • Full keyboard navigation (arrow keys, Enter/Space to select, Escape to dismiss)
  • ARIA roles and labels on suggestion list, hover card, and warning alert
  • Focus management when opening/closing popovers
  • Screen reader announcements for loading, error, and empty states