Default

Loading interactive example. Full source is available below.

View example source
Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import { MessageBar } from "@coreai-ds/react-components";
import { MessageBarBody } from "@coreai-ds/react-components";
import { MessageBarTitle } from "@coreai-ds/react-components";
import { Link } from "@coreai-ds/react-components";
import { MessageBarActions } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { DismissRegular } from "@fluentui/react-icons";

export const Default = () => {
    return (<MessageBar>
        <MessageBarBody>
          <MessageBarTitle>Descriptive title</MessageBarTitle>
          Message providing information to the user with actionable insights. <Link>Link</Link>
        </MessageBarBody>
        <MessageBarActions containerAction={<Button aria-label="dismiss" appearance="transparent" icon={<DismissRegular />}/>}>
          <Button>Action</Button>
          <Button>Action</Button>
        </MessageBarActions>
      </MessageBar>);
};

export default Default;

Resources

Best practices

Do

  • Match intent to the situation: informational, success, warning, or error.
  • Include an action or link in warning and error messages.
  • Stack messages from most critical to least critical.

Don't

  • Use a message bar to prevent a destructive action; use a dialog.
  • Use it for time-sensitive status originating elsewhere; use a toast.
  • Overload the body with long explanations.

Behavior and states

  • Message bar content never truncates.
  • After the second line, reflow pushes actions below the body.
  • Message bars are dismissible with a Close button.
  • A dismissed warning or error reappears in the next session until the problem is resolved.
  • If the message is intended to prevent a destructive action, try a dialog instead.
  • If the message is time-sensitive, but relates to an activity or status from a different location, try a toast notification instead.
API referenceGenerated CoreAI prop and type summaries

API

Generated CoreAI prop summaries, not replacement type declarations. Most native DOM/event and ARIA props are omitted. ? means optional; JSDoc shows defaults, deprecations, and conditional requirements. Defaults assume the standard CoreAI provider.

MessageBar API

interface MessageBarProps {
  as?: "div";

  /**
   * Rendered when the component is in multiline layout to guarantee correct spacing even
   * if no actions are rendered. When actions are rendered, the default actions grid area will render
   * over this element
   *
   * NOTE: If you are using this slot, this probably means that you are using the MessageBar without
   * actions, this is not recommended from an accesibility point of view
   */
  bottomReflowSpacer?: WithSlotShorthandValue<{ as?: "div"; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & { ref?: ((instance: HTMLDivElement | null) => void) | RefObject<HTMLDivElement> | null; }, "children"> & { children?: any; }> | null | undefined;

  children?: any;

  className?: string;

  icon?: WithSlotShorthandValue<{ as?: "div"; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & { ref?: ((instance: HTMLDivElement | null) => void) | RefObject<HTMLDivElement> | null; }, "children"> & { children?: any; }> | null | undefined;

  /**
   * The intent of the message. In addition to Fluent's options, CoreAI adds
   * `"brand"` for a branded informational callout.
   *
   * - `"info"`: Neutral informational surface.
   * - `"warning"`: Warning status ramp.
   * - `"error"`: Danger status ramp.
   * - `"success"`: Success status ramp.
   * - `"brand"`: Brand primary ramp.
   * @default 'info'
   */
  intent?: "brand" | "success" | "warning" | "error" | "info";

  layout?: "auto" | "multiline" | "singleline";

  politeness?: "assertive" | "polite";

  ref?: Ref<HTMLDivElement>;

  /**
   * Use squal for page level messages and rounded for component level messages
   * @default rounded
   */
  shape?: "rounded" | "square";

  style?: CSSProperties;
}

MessageBarActions API

MessageBarActions component

interface MessageBarActionsProps {
  as?: "div";

  children?: any;

  className?: string;

  /**
   * Generally the 'Dismiss' button for the MessageBar
   */
  containerAction?: WithSlotShorthandValue<{ as?: "div"; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & { ref?: ((instance: HTMLDivElement | null) => void) | RefObject<HTMLDivElement> | null; }, "children"> & { children?: any; }> | null | undefined;

  ref?: Ref<HTMLDivElement>;

  style?: CSSProperties;
}

MessageBarBody API

MessageBarBody component

interface MessageBarBodyProps {
  as?: "div";

  children?: any;

  className?: string;

  ref?: Ref<HTMLDivElement>;

  style?: CSSProperties;
}

MessageBarGroup API

MessageBarGroup component

interface MessageBarGroupProps {
  animate?: "both" | "exit-only";

  as?: "div";

  children?: any;

  className?: string;

  ref?: Ref<HTMLDivElement>;

  style?: CSSProperties;
}

MessageBarTitle API

MessageBarTitle component

interface MessageBarTitleProps {
  as?: "span";

  children?: any;

  className?: string;

  ref?: Ref<HTMLSpanElement>;

  style?: CSSProperties;
}

Implementation

CoreAI 0.12.0; Fluent 9.74.9.

Setup and dependencies.

Import components from @coreai-ds/react-components. CoreAI guidance above takes precedence over API demonstration examples.

Actions

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { MessageBar } from "@coreai-ds/react-components";
import { MessageBarBody } from "@coreai-ds/react-components";
import { MessageBarTitle } from "@coreai-ds/react-components";
import { Link } from "@coreai-ds/react-components";
import { MessageBarActions } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { DismissRegular } from "@fluentui/react-icons";
import * as React from 'react';

export const Actions = (): JSXElement => (<MessageBar>
    <MessageBarBody>
      <MessageBarTitle>Descriptive title</MessageBarTitle>
      Message providing information to the user with actionable insights. <Link>Link</Link>
    </MessageBarBody>
    <MessageBarActions containerAction={<Button appearance="transparent" aria-label="Dismiss" icon={<DismissRegular />}/>}>
      <Button>Action</Button>
      <Button>Action</Button>
    </MessageBarActions>
  </MessageBar>);

export default Actions;

Animation

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { tokens } from "@coreai-ds/react-components";
import * as React from 'react';
import type { MessageBarGroupProps } from "@coreai-ds/react-components";
import type { MessageBarIntent } from "@coreai-ds/react-components";
import { Field } from "@coreai-ds/react-components";
import { RadioGroup } from "@coreai-ds/react-components";
import { Radio } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { MessageBarGroup } from "@coreai-ds/react-components";
import { MessageBar } from "@coreai-ds/react-components";
import { MessageBarBody } from "@coreai-ds/react-components";
import { MessageBarTitle } from "@coreai-ds/react-components";
import { Link } from "@coreai-ds/react-components";
import { MessageBarActions } from "@coreai-ds/react-components";
import { DismissRegular } from "@fluentui/react-icons";

const useStyles = makeStyles({
    controlsContainer: {
        display: 'flex',
        flexDirection: 'row',
    },
    messageBarGroup: {
        padding: tokens.spacingHorizontalMNudge,
        display: 'flex',
        flexDirection: 'column',
        marginTop: '10px',
        gap: '10px',
        height: '300px',
        overflow: 'auto',
        border: `2px solid ${tokens.colorBrandForeground1}`,
    },
    field: {
        flexGrow: 1,
        alignItems: 'center',
        gridTemplateColumns: 'max-content auto',
    },
    buttonGroup: {
        display: 'flex',
        gap: '5px',
    },
});

interface ExampleMessage {
    intent: MessageBarIntent;
    id: number;
}

const intents: MessageBarIntent[] = ['info', 'warning', 'error', 'success'];

export const Animation = (): JSXElement => {
    const styles = useStyles();
    const counterRef = React.useRef(0);
    const [animate, setAnimate] = React.useState<MessageBarGroupProps['animate']>('both');
    const [messages, setMessages] = React.useState<ExampleMessage[]>([]);
    const addMessage = () => {
        const intent = intents[Math.floor(Math.random() * intents.length)];
        const newMessage = { intent, id: counterRef.current++ };
        setMessages(s => [newMessage, ...s]);
    };
    const clearMessages = () => setMessages([]);
    const dismissMessage = (messageId: number) => setMessages(s => s.filter(entry => entry.id !== messageId));
    return (<div>
      <div className={styles.controlsContainer}>
        <Field className={styles.field} label="Select animation type:" orientation="horizontal">
          <RadioGroup layout="horizontal" onChange={(_, { value }) => setAnimate(value as MessageBarGroupProps['animate'])} value={animate}>
            <Radio label="both" value="both"/>
            <Radio label="exit-only" value="exit-only"/>
          </RadioGroup>
        </Field>

        <div className={styles.buttonGroup}>
          <Button appearance="primary" onClick={addMessage}>
            Add message
          </Button>
          <Button onClick={clearMessages}>Clear</Button>
        </div>
      </div>

      <MessageBarGroup animate={animate} className={styles.messageBarGroup}>
        {messages.map(({ intent, id }) => (<MessageBar key={`${intent}-${id}`} intent={intent}>
            <MessageBarBody>
              <MessageBarTitle>Descriptive title</MessageBarTitle>
              Message providing information to the user with actionable insights. <Link>Link</Link>
            </MessageBarBody>
            <MessageBarActions containerAction={<Button onClick={() => dismissMessage(id)} aria-label="dismiss" appearance="transparent" icon={<DismissRegular />}/>}/>
          </MessageBar>))}
      </MessageBarGroup>
    </div>);
};

export default Animation;

Dismiss

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { tokens } from "@coreai-ds/react-components";
import * as React from 'react';
import type { MessageBarIntent } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { MessageBarGroup } from "@coreai-ds/react-components";
import { MessageBar } from "@coreai-ds/react-components";
import { MessageBarBody } from "@coreai-ds/react-components";
import { MessageBarTitle } from "@coreai-ds/react-components";
import { Link } from "@coreai-ds/react-components";
import { MessageBarActions } from "@coreai-ds/react-components";
import { DismissRegular } from "@fluentui/react-icons";

const useStyles = makeStyles({
    messageBarGroup: {
        padding: tokens.spacingHorizontalMNudge,
        display: 'flex',
        flexDirection: 'column',
        marginTop: '10px',
        gap: '10px',
        height: '300px',
        overflow: 'auto',
        border: `2px solid ${tokens.colorBrandForeground1}`,
    },
    buttonGroup: {
        display: 'flex',
        justifyContent: 'end',
        gap: '5px',
    },
});

interface ExampleMessage {
    intent: MessageBarIntent;
    id: number;
}

const intents: MessageBarIntent[] = ['info', 'warning', 'error', 'success'];

export const Dismiss = (): JSXElement => {
    const styles = useStyles();
    const counterRef = React.useRef(0);
    const [messages, setMessages] = React.useState<ExampleMessage[]>([]);
    const addMessage = () => {
        const intent = intents[Math.floor(Math.random() * intents.length)];
        const newMessage = { intent, id: counterRef.current++ };
        setMessages(s => [newMessage, ...s]);
    };
    const clearMessages = () => setMessages([]);
    const dismissMessage = (messageId: number) => setMessages(s => s.filter(entry => entry.id !== messageId));
    return (<>
      <div className={styles.buttonGroup}>
        <Button appearance="primary" onClick={addMessage}>
          Add message
        </Button>
        <Button onClick={clearMessages}>Clear</Button>
      </div>

      <MessageBarGroup className={styles.messageBarGroup}>
        {messages.map(({ intent, id }) => (<MessageBar key={`${intent}-${id}`} intent={intent}>
            <MessageBarBody>
              <MessageBarTitle>Descriptive title</MessageBarTitle>
              Message providing information to the user with actionable insights. <Link>Link</Link>
            </MessageBarBody>
            <MessageBarActions containerAction={<Button onClick={() => dismissMessage(id)} aria-label="dismiss" appearance="transparent" icon={<DismissRegular />}/>}/>
          </MessageBar>))}
      </MessageBarGroup>
    </>);
};

export default Dismiss;

Intent

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { MessageBarIntent } from "@coreai-ds/react-components";
import { MessageBar } from "@coreai-ds/react-components";
import { MessageBarBody } from "@coreai-ds/react-components";
import { MessageBarTitle } from "@coreai-ds/react-components";
import { Link } from "@coreai-ds/react-components";

export const Intent = () => {
    // CoreAI adds `"brand"` on top of Fluent's four preset intents.
    const intents: MessageBarIntent[] = ['info', 'warning', 'error', 'success', 'brand'];
    const styles = /* css */ `
      .message-bar-intent-example {
        display: flex;
        flex-direction: column;
        gap: 10px;
      }
    `;
    return (<>
        <style>{styles}</style>
        <div className="message-bar-intent-example">
          {intents.map((intent) => (<MessageBar key={intent} intent={intent}>
              <MessageBarBody>
                <MessageBarTitle>Intent {intent}</MessageBarTitle>
                Message providing information to the user with actionable insights.{' '}
                <Link>Link</Link>
              </MessageBarBody>
            </MessageBar>))}
        </div>
      </>);
};

export default Intent;

Manual Layout

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import * as React from 'react';
import { Switch } from "@coreai-ds/react-components";
import { MessageBar } from "@coreai-ds/react-components";
import { MessageBarBody } from "@coreai-ds/react-components";
import { MessageBarTitle } from "@coreai-ds/react-components";
import { Link } from "@coreai-ds/react-components";
import { MessageBarActions } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { DismissRegular } from "@fluentui/react-icons";

const intents = ['info', 'warning', 'error', 'success'] as const;

export const ManualLayout = (): JSXElement => {
    const [single, setSingle] = React.useState(true);
    return (<>
      <Switch label={single ? 'Single line layout' : 'Multi line layout'} checked={single} onChange={(_, { checked }) => setSingle(checked)}/>
      <div style={{ display: 'flex', flexDirection: 'column', gap: '10px' }}>
        {intents.map(intent => (<MessageBar key={intent} layout={single ? 'singleline' : 'multiline'} intent={intent}>
            <MessageBarBody>
              <MessageBarTitle>Descriptive title</MessageBarTitle>
              Message providing information to the user with actionable insights. <Link>Link</Link>
            </MessageBarBody>
            <MessageBarActions containerAction={<Button aria-label="dismiss" appearance="transparent" icon={<DismissRegular />}/>}>
              <Button>Action</Button>
              <Button>Action</Button>
            </MessageBarActions>
          </MessageBar>))}
      </div>
    </>);
};

export default ManualLayout;

Reflow

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { tokens } from "@coreai-ds/react-components";
import * as React from 'react';
import { Switch } from "@coreai-ds/react-components";
import { mergeClasses } from "@coreai-ds/react-components";
import { MessageBar } from "@coreai-ds/react-components";
import { MessageBarBody } from "@coreai-ds/react-components";
import { MessageBarTitle } from "@coreai-ds/react-components";
import { Link } from "@coreai-ds/react-components";
import { MessageBarActions } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { DismissRegular } from "@fluentui/react-icons";

const useStyles = makeStyles({
    compact: {
        width: '600px',
    },
    resizableArea: {
        display: 'flex',
        flexDirection: 'column',
        padding: '30px 10px',
        gap: '10px',
        border: `2px solid ${tokens.colorBrandBackground}`,
        position: 'relative',
        overflow: 'hidden',
        '::after': {
            content: `'Resizable Area'`,
            position: 'absolute',
            padding: '1px 4px 1px',
            top: '-2px',
            left: '-2px',
            fontFamily: 'monospace',
            fontSize: '15px',
            fontWeight: 900,
            lineHeight: 1,
            letterSpacing: '1px',
            color: tokens.colorNeutralForegroundOnBrand,
            backgroundColor: tokens.colorBrandBackground,
        },
    },
});

export const Reflow = (): JSXElement => {
    const styles = useStyles();
    const [compact, setCompact] = React.useState(true);
    return (<>
      <Switch label={compact ? 'Compact width' : 'Full width'} checked={compact} onChange={(_, { checked }) => setCompact(checked)}/>
      <div className={mergeClasses(styles.resizableArea, compact && styles.compact)}>
        <MessageBar intent="success">
          <MessageBarBody>
            <MessageBarTitle>Descriptive title</MessageBarTitle>
            Message providing information to the user with actionable insights. <Link>Link</Link>
          </MessageBarBody>
          <MessageBarActions containerAction={<Button aria-label="dismiss" appearance="transparent" icon={<DismissRegular />}/>}>
            <Button>Action</Button>
            <Button>Action</Button>
          </MessageBarActions>
        </MessageBar>
      </div>
    </>);
};

export default Reflow;

Shape

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { MessageBar } from "@coreai-ds/react-components";
import { MessageBarBody } from "@coreai-ds/react-components";
import { MessageBarTitle } from "@coreai-ds/react-components";
import * as React from 'react';

const useClasses = makeStyles({
    container: {
        display: 'flex',
        flexDirection: 'column',
        gap: '10px',
    },
});

export const Shape = (): JSXElement => {
    const classes = useClasses();
    return (<div className={classes.container}>
      <MessageBar shape="rounded">
        <MessageBarBody>
          <MessageBarTitle>Rounded shape</MessageBarTitle>
          This message has rounded shape.
        </MessageBarBody>
      </MessageBar>
      <MessageBar shape="square">
        <MessageBarBody>
          <MessageBarTitle>Square shape</MessageBarTitle>
          This message has square shape.
        </MessageBarBody>
      </MessageBar>
    </div>);
};

export default Shape;