I try to use a good pattern to use the Callout, for instance when hovering over a Persona element. Currently I do the following:

  • _clientPersonaElement is a reference to the Element the Callout uses as location: Callout.target
  • state.clientCalloutVisible is set by _onShowClientCallout to show the Callout. It is reset by _onClientCalloutDismiss

Here the code:

export default class ILoggerListItem extends React.Component<IILoggerListItemProps,IILoggerListItemState> {
    private _clientPersonaElement: HTMLElement;

    constructor(props: IILoggerListItemProps) {

        this._onShowClientCallout = this._onShowClientCallout.bind(this);
        this._onClientCalloutDismiss = this._onClientCalloutDismiss.bind(this);

        this.state = {
          clientCalloutVisible: false

    private _onShowClientCallout(person: IInteractionLogPerson, event: React.MouseEvent<Persona>) {
        if(! this.state.clientCalloutVisible)
                clientCalloutVisible: true,

    private _onClientCalloutDismiss() {
        if( this.state.clientCalloutVisible)
                clientCalloutVisible: false

My render looks like:

public render(): JSX.Element {

return (
    className={ classILoggerItem }
    data-is-focusable={ true } >
    <FocusZone direction={ FocusZoneDirection.horizontal }>
      <div className={ css(styles.itemTaskRow, 'ms-Grid-row') }>

        <div className= {css( 'ms-Grid-col', 'ms-u-sm4')}
          ref={ (targetElement) => this._clientPersonaElement = targetElement } >
            onMouseOver= {(event) => this._onShowClientCallout(person, event)}
            size= { PersonaSize.regular }
            imageUrl= { person.Picture }
            primaryText= { person.Title }
            secondaryText= { person.MobilePhone }

    { this.state.clientCalloutVisible && (
        className={ css(styles.iLoggerClientCallout ) }
        gapSpace={ 0 }
        onDismiss={ this._onClientCalloutDismiss }
        setInitialFocus={ true }
        <div className={ css(styles.iLoggerClientCalloutHeader) }>
          <p className={ css(styles.iLoggerClientCalloutTitle, 'ms-font-l') }>
            { this.props.item.Client.Title }
        <div className={ css(styles.iLoggerClientCalloutInner) }>
          <div className={ css(styles.iLoggerClientCalloutContent) }>
            <p className={ css(styles.iLoggerClientCalloutSubText, 'ms-font-m') }>
              { this.props.item.Client.MobilePhone } <br />
              { this.props.item.Client.EMail }
          <div className={ css(styles.iLoggerClientCalloutActions) }>
            <Link className={ css(styles.iLoggerClientCalloutLink) } href='http://microsoft.com'>Go to profile</Link>
    ) }

I wrap the Persona element in a Div element, so I can get a reference used for the target property of the Callout:

I couldn't get ref=.. on the PersonA to work, because it's not an HtmlElement.

  • target of the Callout can be a MouseEvent, but I couldn't figure out, how to get the Persona.onMouseOver as a MouseEvent.
  • target can be a querySelector string of a valid HTMLElement . Is it possible to reference the Persona element via a querySelector?

Is this a good pattern with the additional div element and ref=.. ? Or would using MouseEvent or querySelector better?

Every feedback is valued and appreciated :-)

  • 1
    Is there any error logs on your browser console? Start by putting a debugger on _onShowClientCallout function and check if it is invoking or not. – ThinkB4Code Jul 6 '17 at 5:36
  • The above code is working. I don't know how to use the MouseEvent for the Callout.target. I tried using the React.MouseEvent<Persona> passed to the onMouseEnter handler, but it failed, because it is not of type MouseEvent. Is the <div> wrapper the best approach for this? – Dennis Kuhn Jul 6 '17 at 6:18
  • Yes, as a workaround and for testing purpose attaching it to wrapper div mouse event is good approach. – ThinkB4Code Jul 6 '17 at 6:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.