+`;
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBar/getIntentIcon.tsx b/packages/react-components/react-message-bar-preview/src/components/MessageBar/getIntentIcon.tsx
new file mode 100644
index 0000000000000..8b8f345ce332f
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBar/getIntentIcon.tsx
@@ -0,0 +1,19 @@
+import * as React from 'react';
+import { MessageBarProps } from './MessageBar.types';
+import { CheckmarkCircleFilled, InfoFilled, WarningFilled, ErrorCircleFilled } from '@fluentui/react-icons';
+
+export function getIntentIcon(intent: MessageBarProps['intent']) {
+ switch (intent) {
+ case 'info':
+ return ;
+ case 'warning':
+ return ;
+ case 'error':
+ return ;
+ case 'success':
+ return ;
+
+ default:
+ return null;
+ }
+}
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBar/index.ts b/packages/react-components/react-message-bar-preview/src/components/MessageBar/index.ts
new file mode 100644
index 0000000000000..1b87b685202c5
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBar/index.ts
@@ -0,0 +1,5 @@
+export * from './MessageBar';
+export * from './MessageBar.types';
+export * from './renderMessageBar';
+export * from './useMessageBar';
+export * from './useMessageBarStyles.styles';
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBar/renderMessageBar.tsx b/packages/react-components/react-message-bar-preview/src/components/MessageBar/renderMessageBar.tsx
new file mode 100644
index 0000000000000..83aa749e3d1ef
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBar/renderMessageBar.tsx
@@ -0,0 +1,22 @@
+/** @jsxRuntime automatic */
+/** @jsxImportSource @fluentui/react-jsx-runtime */
+
+import { assertSlots } from '@fluentui/react-utilities';
+import type { MessageBarState, MessageBarSlots, MessageBarContextValues } from './MessageBar.types';
+import { MessageBarContextProvider } from '../../contexts/messageBarContext';
+
+/**
+ * Render the final JSX of MessageBar
+ */
+export const renderMessageBar_unstable = (state: MessageBarState, contexts: MessageBarContextValues) => {
+ assertSlots(state);
+
+ return (
+
+
+ {state.icon && }
+ {state.root.children}
+
+
+ );
+};
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBar/useMessageBar.ts b/packages/react-components/react-message-bar-preview/src/components/MessageBar/useMessageBar.ts
new file mode 100644
index 0000000000000..b9759360a050d
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBar/useMessageBar.ts
@@ -0,0 +1,39 @@
+import * as React from 'react';
+import { getNativeElementProps, slot } from '@fluentui/react-utilities';
+import type { MessageBarProps, MessageBarState } from './MessageBar.types';
+import { getIntentIcon } from './getIntentIcon';
+
+/**
+ * Create the state required to render MessageBar.
+ *
+ * The returned state can be modified with hooks such as useMessageBarStyles_unstable,
+ * before being passed to renderMessageBar_unstable.
+ *
+ * @param props - props from this instance of MessageBar
+ * @param ref - reference to root HTMLElement of MessageBar
+ */
+export const useMessageBar_unstable = (props: MessageBarProps, ref: React.Ref): MessageBarState => {
+ const { layout = 'singleline', intent = 'info' } = props;
+
+ return {
+ components: {
+ root: 'div',
+ icon: 'div',
+ },
+ root: slot.always(
+ getNativeElementProps('div', {
+ ref,
+ ...props,
+ }),
+ { elementType: 'div' },
+ ),
+
+ icon: slot.optional(props.icon, {
+ renderByDefault: true,
+ elementType: 'div',
+ defaultProps: { children: getIntentIcon(intent) },
+ }),
+ layout,
+ intent,
+ };
+};
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBar/useMessageBarContextValues.ts b/packages/react-components/react-message-bar-preview/src/components/MessageBar/useMessageBarContextValues.ts
new file mode 100644
index 0000000000000..c3f1d5322b479
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBar/useMessageBarContextValues.ts
@@ -0,0 +1,17 @@
+import * as React from 'react';
+import { MessageBarContextValues, MessageBarState } from './MessageBar.types';
+
+export function useMessageBarContextValue_unstable(state: MessageBarState): MessageBarContextValues {
+ const { layout } = state;
+
+ const messageBarContext = React.useMemo(
+ () => ({
+ layout,
+ }),
+ [layout],
+ );
+
+ return {
+ messageBar: messageBarContext,
+ };
+}
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBar/useMessageBarStyles.styles.ts b/packages/react-components/react-message-bar-preview/src/components/MessageBar/useMessageBarStyles.styles.ts
new file mode 100644
index 0000000000000..974c68afba45f
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBar/useMessageBarStyles.styles.ts
@@ -0,0 +1,109 @@
+import { makeResetStyles, makeStyles, mergeClasses, shorthands } from '@griffel/react';
+import { tokens } from '@fluentui/react-theme';
+import type { SlotClassNames } from '@fluentui/react-utilities';
+import type { MessageBarSlots, MessageBarState } from './MessageBar.types';
+
+export const messageBarClassNames: SlotClassNames = {
+ root: 'fui-MessageBar',
+ icon: 'fui-MessageBar__icon',
+};
+
+const useRootBaseStyles = makeResetStyles({
+ display: 'grid',
+ gridTemplateColumns: 'auto 1fr auto auto',
+ gridTemplateAreas: '"icon body secondaryActions actions"',
+ ...shorthands.padding('0', tokens.spacingHorizontalM),
+ ...shorthands.border(tokens.strokeWidthThin, 'solid', tokens.colorNeutralStroke1),
+ ...shorthands.borderRadius(tokens.borderRadiusMedium),
+ alignItems: 'center',
+ minHeight: '36px',
+ boxSizing: 'border-box',
+ backgroundColor: tokens.colorNeutralBackground3,
+});
+
+const useIconBaseStyles = makeResetStyles({
+ ...shorthands.gridArea('icon'),
+ fontSize: tokens.fontSizeBase500,
+ marginRight: tokens.spacingHorizontalS,
+ color: tokens.colorNeutralForeground3,
+});
+
+const useMultilineStyles = makeStyles({
+ rootMultiline: {
+ paddingTop: tokens.spacingVerticalMNudge,
+ gridTemplateColumns: 'auto 1fr auto',
+ gridTemplateAreas: `
+ "icon body actions"
+ "secondaryActions secondaryActions secondaryActions"
+ `,
+ },
+
+ secondaryActionsMultiline: {
+ justifyContent: 'end',
+ marginTop: tokens.spacingVerticalMNudge,
+ marginBottom: tokens.spacingVerticalS,
+ marginRight: '0px',
+ },
+});
+
+const useIconIntentStyles = makeStyles({
+ info: {
+ /** already in base reset styles */
+ },
+ error: {
+ color: tokens.colorStatusDangerForeground1,
+ },
+ warning: {
+ color: tokens.colorStatusWarningForeground3,
+ },
+ success: {
+ color: tokens.colorStatusSuccessForeground1,
+ },
+});
+
+const useRootIntentStyles = makeStyles({
+ info: {
+ /** already in base reset styles */
+ },
+ error: {
+ backgroundColor: tokens.colorStatusDangerBackground1,
+ ...shorthands.borderColor(tokens.colorStatusDangerBorder1),
+ },
+ warning: {
+ backgroundColor: tokens.colorStatusWarningBackground1,
+ ...shorthands.borderColor(tokens.colorStatusWarningBorder1),
+ },
+ success: {
+ backgroundColor: tokens.colorStatusSuccessBackground1,
+ ...shorthands.borderColor(tokens.colorStatusSuccessBorder1),
+ },
+});
+
+/**
+ * Apply styling to the MessageBar slots based on the state
+ */
+export const useMessageBarStyles_unstable = (state: MessageBarState): MessageBarState => {
+ const rootBaseStyles = useRootBaseStyles();
+ const iconBaseStyles = useIconBaseStyles();
+ const multilineStyles = useMultilineStyles();
+ const iconIntentStyles = useIconIntentStyles();
+ const rootIntntStyles = useRootIntentStyles();
+ state.root.className = mergeClasses(
+ messageBarClassNames.root,
+ rootBaseStyles,
+ state.layout === 'multiline' && multilineStyles.rootMultiline,
+ rootIntntStyles[state.intent],
+ state.root.className,
+ );
+
+ if (state.icon) {
+ state.icon.className = mergeClasses(
+ messageBarClassNames.icon,
+ iconBaseStyles,
+ iconIntentStyles[state.intent],
+ state.icon.className,
+ );
+ }
+
+ return state;
+};
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBarActions/MessageBarActions.test.tsx b/packages/react-components/react-message-bar-preview/src/components/MessageBarActions/MessageBarActions.test.tsx
new file mode 100644
index 0000000000000..d62960938f7ba
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBarActions/MessageBarActions.test.tsx
@@ -0,0 +1,23 @@
+import * as React from 'react';
+import { render } from '@testing-library/react';
+import { isConformant } from '../../testing/isConformant';
+import { MessageBarActions } from './MessageBarActions';
+import { MessageBarActionsProps } from './MessageBarActions.types';
+
+describe('MessageBarActions', () => {
+ isConformant({
+ Component: MessageBarActions,
+ displayName: 'MessageBarActions',
+ disabledTests: [
+ // TODO: having problems due to the fact root of DialogTitle is Fragment
+ 'component-has-static-classnames-object',
+ ],
+ });
+
+ // TODO add more tests here, and create visual regression tests in /apps/vr-tests
+
+ it('renders a default state', () => {
+ const result = render(Default MessageBarActions);
+ expect(result.container).toMatchSnapshot();
+ });
+});
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBarActions/MessageBarActions.tsx b/packages/react-components/react-message-bar-preview/src/components/MessageBarActions/MessageBarActions.tsx
new file mode 100644
index 0000000000000..ca28530fe5939
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBarActions/MessageBarActions.tsx
@@ -0,0 +1,18 @@
+import * as React from 'react';
+import type { ForwardRefComponent } from '@fluentui/react-utilities';
+import { useMessageBarActions_unstable } from './useMessageBarActions';
+import { renderMessageBarActions_unstable } from './renderMessageBarActions';
+import { useMessageBarActionsStyles_unstable } from './useMessageBarActionsStyles.styles';
+import type { MessageBarActionsProps } from './MessageBarActions.types';
+
+/**
+ * MessageBarActions component - TODO: add more docs
+ */
+export const MessageBarActions: ForwardRefComponent = React.forwardRef((props, ref) => {
+ const state = useMessageBarActions_unstable(props, ref);
+
+ useMessageBarActionsStyles_unstable(state);
+ return renderMessageBarActions_unstable(state);
+});
+
+MessageBarActions.displayName = 'MessageBarActions';
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBarActions/MessageBarActions.types.ts b/packages/react-components/react-message-bar-preview/src/components/MessageBarActions/MessageBarActions.types.ts
new file mode 100644
index 0000000000000..796972f7bbf8e
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBarActions/MessageBarActions.types.ts
@@ -0,0 +1,18 @@
+import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';
+import { MessageBarContextValue } from '../../contexts/messageBarContext';
+
+export type MessageBarActionsSlots = {
+ root: Slot<'div'>;
+ containerAction?: Slot<'div'>;
+};
+
+/**
+ * MessageBarActions Props
+ */
+export type MessageBarActionsProps = ComponentProps & {};
+
+/**
+ * State used in rendering MessageBarActions
+ */
+export type MessageBarActionsState = ComponentState &
+ Pick, 'layout'>;
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBarActions/__snapshots__/MessageBarActions.test.tsx.snap b/packages/react-components/react-message-bar-preview/src/components/MessageBarActions/__snapshots__/MessageBarActions.test.tsx.snap
new file mode 100644
index 0000000000000..aa2eebdf434aa
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBarActions/__snapshots__/MessageBarActions.test.tsx.snap
@@ -0,0 +1,11 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`MessageBarActions renders a default state 1`] = `
+
+
+ Default MessageBarActions
+
+
+`;
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBarActions/index.ts b/packages/react-components/react-message-bar-preview/src/components/MessageBarActions/index.ts
new file mode 100644
index 0000000000000..d8ba24f39657b
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBarActions/index.ts
@@ -0,0 +1,5 @@
+export * from './MessageBarActions';
+export * from './MessageBarActions.types';
+export * from './renderMessageBarActions';
+export * from './useMessageBarActions';
+export * from './useMessageBarActionsStyles.styles';
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBarActions/renderMessageBarActions.tsx b/packages/react-components/react-message-bar-preview/src/components/MessageBarActions/renderMessageBarActions.tsx
new file mode 100644
index 0000000000000..15ddc4bf084e3
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBarActions/renderMessageBarActions.tsx
@@ -0,0 +1,28 @@
+/** @jsxRuntime automatic */
+/** @jsxImportSource @fluentui/react-jsx-runtime */
+
+import { assertSlots } from '@fluentui/react-utilities';
+import type { MessageBarActionsState, MessageBarActionsSlots } from './MessageBarActions.types';
+import { ButtonContextProvider } from '@fluentui/react-button';
+
+/**
+ * Render the final JSX of MessageBarActions
+ */
+export const renderMessageBarActions_unstable = (state: MessageBarActionsState) => {
+ assertSlots(state);
+ if (state.layout === 'multiline') {
+ return (
+
+ {state.containerAction && }
+
+
+ );
+ }
+
+ return (
+
+
+ {state.containerAction && }
+
+ );
+};
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBarActions/useMessageBarActions.ts b/packages/react-components/react-message-bar-preview/src/components/MessageBarActions/useMessageBarActions.ts
new file mode 100644
index 0000000000000..5ccf97a36a718
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBarActions/useMessageBarActions.ts
@@ -0,0 +1,35 @@
+import * as React from 'react';
+import { getNativeElementProps, slot } from '@fluentui/react-utilities';
+import type { MessageBarActionsProps, MessageBarActionsState } from './MessageBarActions.types';
+import { useMessageBarContext } from '../../contexts/messageBarContext';
+
+/**
+ * Create the state required to render MessageBarActions.
+ *
+ * The returned state can be modified with hooks such as useMessageBarActionsStyles_unstable,
+ * before being passed to renderMessageBarActions_unstable.
+ *
+ * @param props - props from this instance of MessageBarActions
+ * @param ref - reference to root HTMLElement of MessageBarActions
+ */
+export const useMessageBarActions_unstable = (
+ props: MessageBarActionsProps,
+ ref: React.Ref,
+): MessageBarActionsState => {
+ const { layout = 'singleline' } = useMessageBarContext();
+ return {
+ components: {
+ root: 'div',
+ containerAction: 'div',
+ },
+ containerAction: slot.optional(props.containerAction, { renderByDefault: false, elementType: 'div' }),
+ root: slot.always(
+ getNativeElementProps('div', {
+ ref,
+ ...props,
+ }),
+ { elementType: 'div' },
+ ),
+ layout,
+ };
+};
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBarActions/useMessageBarActionsStyles.styles.ts b/packages/react-components/react-message-bar-preview/src/components/MessageBarActions/useMessageBarActionsStyles.styles.ts
new file mode 100644
index 0000000000000..dead8bcab465b
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBarActions/useMessageBarActionsStyles.styles.ts
@@ -0,0 +1,58 @@
+import { makeResetStyles, makeStyles, mergeClasses, shorthands } from '@griffel/react';
+import type { SlotClassNames } from '@fluentui/react-utilities';
+import { tokens } from '@fluentui/react-theme';
+import type { MessageBarActionsSlots, MessageBarActionsState } from './MessageBarActions.types';
+
+export const messageBarActionsClassNames: SlotClassNames = {
+ root: 'fui-MessageBarActions',
+ containerAction: 'fui-MessageBarActions__containerAction',
+};
+
+/**
+ * Styles for the root slot
+ */
+const useRootBaseStyles = makeResetStyles({
+ ...shorthands.gridArea('secondaryActions'),
+ display: 'flex',
+ alignItems: 'center',
+ columnGap: tokens.spacingHorizontalM,
+ marginRight: tokens.spacingHorizontalM,
+});
+
+const useContainerActionBaseStyles = makeResetStyles({
+ ...shorthands.gridArea('actions'),
+});
+
+const useMultilineStyles = makeStyles({
+ root: {
+ justifyContent: 'end',
+ marginTop: tokens.spacingVerticalMNudge,
+ marginBottom: tokens.spacingVerticalS,
+ marginRight: '0px',
+ },
+});
+
+/**
+ * Apply styling to the MessageBarActions slots based on the state
+ */
+export const useMessageBarActionsStyles_unstable = (state: MessageBarActionsState): MessageBarActionsState => {
+ const rootBaseStyles = useRootBaseStyles();
+ const containerActionBaseStyles = useContainerActionBaseStyles();
+ const multilineStyles = useMultilineStyles();
+ state.root.className = mergeClasses(
+ messageBarActionsClassNames.root,
+ rootBaseStyles,
+ state.layout === 'multiline' && multilineStyles.root,
+ state.root.className,
+ );
+
+ if (state.containerAction) {
+ state.containerAction.className = mergeClasses(
+ messageBarActionsClassNames.containerAction,
+ containerActionBaseStyles,
+ state.containerAction.className,
+ );
+ }
+
+ return state;
+};
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBarBody/MessageBarBody.test.tsx b/packages/react-components/react-message-bar-preview/src/components/MessageBarBody/MessageBarBody.test.tsx
new file mode 100644
index 0000000000000..b0bc0a9968aa1
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBarBody/MessageBarBody.test.tsx
@@ -0,0 +1,16 @@
+import * as React from 'react';
+import { render } from '@testing-library/react';
+import { isConformant } from '../../testing/isConformant';
+import { MessageBarBody } from './MessageBarBody';
+
+describe('MessageBarBody', () => {
+ isConformant({
+ Component: MessageBarBody,
+ displayName: 'MessageBarBody',
+ });
+
+ it('renders a default state', () => {
+ const result = render(Default MessageBarBody);
+ expect(result.container).toMatchSnapshot();
+ });
+});
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBarBody/MessageBarBody.tsx b/packages/react-components/react-message-bar-preview/src/components/MessageBarBody/MessageBarBody.tsx
new file mode 100644
index 0000000000000..21e15ad108048
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBarBody/MessageBarBody.tsx
@@ -0,0 +1,18 @@
+import * as React from 'react';
+import type { ForwardRefComponent } from '@fluentui/react-utilities';
+import { useMessageBarBody_unstable } from './useMessageBarBody';
+import { renderMessageBarBody_unstable } from './renderMessageBarBody';
+import { useMessageBarBodyStyles_unstable } from './useMessageBarBodyStyles.styles';
+import type { MessageBarBodyProps } from './MessageBarBody.types';
+
+/**
+ * MessageBarBody component
+ */
+export const MessageBarBody: ForwardRefComponent = React.forwardRef((props, ref) => {
+ const state = useMessageBarBody_unstable(props, ref);
+
+ useMessageBarBodyStyles_unstable(state);
+ return renderMessageBarBody_unstable(state);
+});
+
+MessageBarBody.displayName = 'MessageBarBody';
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBarBody/MessageBarBody.types.ts b/packages/react-components/react-message-bar-preview/src/components/MessageBarBody/MessageBarBody.types.ts
new file mode 100644
index 0000000000000..f471468f316af
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBarBody/MessageBarBody.types.ts
@@ -0,0 +1,15 @@
+import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';
+
+export type MessageBarBodySlots = {
+ root: Slot<'div'>;
+};
+
+/**
+ * MessageBarBody Props
+ */
+export type MessageBarBodyProps = ComponentProps & {};
+
+/**
+ * State used in rendering MessageBarBody
+ */
+export type MessageBarBodyState = ComponentState;
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBarBody/__snapshots__/MessageBarBody.test.tsx.snap b/packages/react-components/react-message-bar-preview/src/components/MessageBarBody/__snapshots__/MessageBarBody.test.tsx.snap
new file mode 100644
index 0000000000000..4c73379056bad
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBarBody/__snapshots__/MessageBarBody.test.tsx.snap
@@ -0,0 +1,11 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`MessageBarBody renders a default state 1`] = `
+
+
+ Default MessageBarBody
+
+
+`;
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBarBody/index.ts b/packages/react-components/react-message-bar-preview/src/components/MessageBarBody/index.ts
new file mode 100644
index 0000000000000..360550329c1df
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBarBody/index.ts
@@ -0,0 +1,5 @@
+export * from './MessageBarBody';
+export * from './MessageBarBody.types';
+export * from './renderMessageBarBody';
+export * from './useMessageBarBody';
+export * from './useMessageBarBodyStyles.styles';
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBarBody/renderMessageBarBody.tsx b/packages/react-components/react-message-bar-preview/src/components/MessageBarBody/renderMessageBarBody.tsx
new file mode 100644
index 0000000000000..fa5e80f1b3da2
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBarBody/renderMessageBarBody.tsx
@@ -0,0 +1,14 @@
+/** @jsxRuntime automatic */
+/** @jsxImportSource @fluentui/react-jsx-runtime */
+
+import { assertSlots } from '@fluentui/react-utilities';
+import type { MessageBarBodyState, MessageBarBodySlots } from './MessageBarBody.types';
+
+/**
+ * Render the final JSX of MessageBarBody
+ */
+export const renderMessageBarBody_unstable = (state: MessageBarBodyState) => {
+ assertSlots(state);
+
+ return ;
+};
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBarBody/useMessageBarBody.ts b/packages/react-components/react-message-bar-preview/src/components/MessageBarBody/useMessageBarBody.ts
new file mode 100644
index 0000000000000..ed99cf2f18a9b
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBarBody/useMessageBarBody.ts
@@ -0,0 +1,30 @@
+import * as React from 'react';
+import { getNativeElementProps, slot } from '@fluentui/react-utilities';
+import type { MessageBarBodyProps, MessageBarBodyState } from './MessageBarBody.types';
+
+/**
+ * Create the state required to render MessageBarBody.
+ *
+ * The returned state can be modified with hooks such as useMessageBarBodyStyles_unstable,
+ * before being passed to renderMessageBarBody_unstable.
+ *
+ * @param props - props from this instance of MessageBarBody
+ * @param ref - reference to root HTMLElement of MessageBarBody
+ */
+export const useMessageBarBody_unstable = (
+ props: MessageBarBodyProps,
+ ref: React.Ref,
+): MessageBarBodyState => {
+ return {
+ components: {
+ root: 'div',
+ },
+ root: slot.always(
+ getNativeElementProps('div', {
+ ref,
+ ...props,
+ }),
+ { elementType: 'div' },
+ ),
+ };
+};
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBarBody/useMessageBarBodyStyles.styles.ts b/packages/react-components/react-message-bar-preview/src/components/MessageBarBody/useMessageBarBodyStyles.styles.ts
new file mode 100644
index 0000000000000..1e470a13b0ba1
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBarBody/useMessageBarBodyStyles.styles.ts
@@ -0,0 +1,23 @@
+import { makeResetStyles, mergeClasses, shorthands } from '@griffel/react';
+import type { SlotClassNames } from '@fluentui/react-utilities';
+import type { MessageBarBodySlots, MessageBarBodyState } from './MessageBarBody.types';
+import { typographyStyles } from '@fluentui/react-theme';
+
+export const messageBarBodyClassNames: SlotClassNames = {
+ root: 'fui-MessageBarBody',
+};
+
+const useRootBaseStyles = makeResetStyles({
+ ...typographyStyles.body1,
+ ...shorthands.gridArea('body'),
+});
+
+/**
+ * Apply styling to the MessageBarBody slots based on the state
+ */
+export const useMessageBarBodyStyles_unstable = (state: MessageBarBodyState): MessageBarBodyState => {
+ const rootBaseStyles = useRootBaseStyles();
+ state.root.className = mergeClasses(messageBarBodyClassNames.root, rootBaseStyles, state.root.className);
+
+ return state;
+};
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBarTitle/MessageBarTitle.test.tsx b/packages/react-components/react-message-bar-preview/src/components/MessageBarTitle/MessageBarTitle.test.tsx
new file mode 100644
index 0000000000000..c34b6a2446dbc
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBarTitle/MessageBarTitle.test.tsx
@@ -0,0 +1,18 @@
+import * as React from 'react';
+import { render } from '@testing-library/react';
+import { isConformant } from '../../testing/isConformant';
+import { MessageBarTitle } from './MessageBarTitle';
+
+describe('MessageBarTitle', () => {
+ isConformant({
+ Component: MessageBarTitle,
+ displayName: 'MessageBarTitle',
+ });
+
+ // TODO add more tests here, and create visual regression tests in /apps/vr-tests
+
+ it('renders a default state', () => {
+ const result = render(Default MessageBarTitle);
+ expect(result.container).toMatchSnapshot();
+ });
+});
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBarTitle/MessageBarTitle.tsx b/packages/react-components/react-message-bar-preview/src/components/MessageBarTitle/MessageBarTitle.tsx
new file mode 100644
index 0000000000000..6ce8533ca2ec6
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBarTitle/MessageBarTitle.tsx
@@ -0,0 +1,18 @@
+import * as React from 'react';
+import type { ForwardRefComponent } from '@fluentui/react-utilities';
+import { useMessageBarTitle_unstable } from './useMessageBarTitle';
+import { renderMessageBarTitle_unstable } from './renderMessageBarTitle';
+import { useMessageBarTitleStyles_unstable } from './useMessageBarTitleStyles.styles';
+import type { MessageBarTitleProps } from './MessageBarTitle.types';
+
+/**
+ * MessageBarTitle component
+ */
+export const MessageBarTitle: ForwardRefComponent = React.forwardRef((props, ref) => {
+ const state = useMessageBarTitle_unstable(props, ref);
+
+ useMessageBarTitleStyles_unstable(state);
+ return renderMessageBarTitle_unstable(state);
+});
+
+MessageBarTitle.displayName = 'MessageBarTitle';
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBarTitle/MessageBarTitle.types.ts b/packages/react-components/react-message-bar-preview/src/components/MessageBarTitle/MessageBarTitle.types.ts
new file mode 100644
index 0000000000000..d966942d2b9fd
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBarTitle/MessageBarTitle.types.ts
@@ -0,0 +1,15 @@
+import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';
+
+export type MessageBarTitleSlots = {
+ root: Slot<'span'>;
+};
+
+/**
+ * MessageBarTitle Props
+ */
+export type MessageBarTitleProps = ComponentProps & {};
+
+/**
+ * State used in rendering MessageBarTitle
+ */
+export type MessageBarTitleState = ComponentState;
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBarTitle/__snapshots__/MessageBarTitle.test.tsx.snap b/packages/react-components/react-message-bar-preview/src/components/MessageBarTitle/__snapshots__/MessageBarTitle.test.tsx.snap
new file mode 100644
index 0000000000000..8d96636aac25e
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBarTitle/__snapshots__/MessageBarTitle.test.tsx.snap
@@ -0,0 +1,11 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`MessageBarTitle renders a default state 1`] = `
+
+
+ Default MessageBarTitle
+
+
+`;
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBarTitle/index.ts b/packages/react-components/react-message-bar-preview/src/components/MessageBarTitle/index.ts
new file mode 100644
index 0000000000000..4bcb0e7df960b
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBarTitle/index.ts
@@ -0,0 +1,5 @@
+export * from './MessageBarTitle';
+export * from './MessageBarTitle.types';
+export * from './renderMessageBarTitle';
+export * from './useMessageBarTitle';
+export * from './useMessageBarTitleStyles.styles';
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBarTitle/renderMessageBarTitle.tsx b/packages/react-components/react-message-bar-preview/src/components/MessageBarTitle/renderMessageBarTitle.tsx
new file mode 100644
index 0000000000000..6b008739d5dcb
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBarTitle/renderMessageBarTitle.tsx
@@ -0,0 +1,19 @@
+/** @jsxRuntime automatic */
+/** @jsxImportSource @fluentui/react-jsx-runtime */
+
+import { assertSlots } from '@fluentui/react-utilities';
+import type { MessageBarTitleState, MessageBarTitleSlots } from './MessageBarTitle.types';
+
+/**
+ * Render the final JSX of MessageBarTitle
+ */
+export const renderMessageBarTitle_unstable = (state: MessageBarTitleState) => {
+ assertSlots(state);
+
+ // TODO Add additional slots in the appropriate place
+ return (
+ <>
+
+ >
+ );
+};
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBarTitle/useMessageBarTitle.ts b/packages/react-components/react-message-bar-preview/src/components/MessageBarTitle/useMessageBarTitle.ts
new file mode 100644
index 0000000000000..87329b8eba488
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBarTitle/useMessageBarTitle.ts
@@ -0,0 +1,30 @@
+import * as React from 'react';
+import { getNativeElementProps, slot } from '@fluentui/react-utilities';
+import type { MessageBarTitleProps, MessageBarTitleState } from './MessageBarTitle.types';
+
+/**
+ * Create the state required to render MessageBarTitle.
+ *
+ * The returned state can be modified with hooks such as useMessageBarTitleStyles_unstable,
+ * before being passed to renderMessageBarTitle_unstable.
+ *
+ * @param props - props from this instance of MessageBarTitle
+ * @param ref - reference to root HTMLElement of MessageBarTitle
+ */
+export const useMessageBarTitle_unstable = (
+ props: MessageBarTitleProps,
+ ref: React.Ref,
+): MessageBarTitleState => {
+ return {
+ components: {
+ root: 'span',
+ },
+ root: slot.always(
+ getNativeElementProps('span', {
+ ref,
+ ...props,
+ }),
+ { elementType: 'span' },
+ ),
+ };
+};
diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBarTitle/useMessageBarTitleStyles.styles.ts b/packages/react-components/react-message-bar-preview/src/components/MessageBarTitle/useMessageBarTitleStyles.styles.ts
new file mode 100644
index 0000000000000..7bc54ff127ac8
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/components/MessageBarTitle/useMessageBarTitleStyles.styles.ts
@@ -0,0 +1,28 @@
+import { makeResetStyles, mergeClasses } from '@griffel/react';
+import { typographyStyles } from '@fluentui/react-theme';
+import type { SlotClassNames } from '@fluentui/react-utilities';
+import type { MessageBarTitleSlots, MessageBarTitleState } from './MessageBarTitle.types';
+
+export const messageBarTitleClassNames: SlotClassNames = {
+ root: 'fui-MessageBarTitle',
+};
+
+/**
+ * Styles for the root slot
+ */
+const useRootBaseStyles = makeResetStyles({
+ ...typographyStyles.body1Strong,
+ '::after': {
+ content: '" "',
+ },
+});
+
+/**
+ * Apply styling to the MessageBarTitle slots based on the state
+ */
+export const useMessageBarTitleStyles_unstable = (state: MessageBarTitleState): MessageBarTitleState => {
+ const rootBaseStyles = useRootBaseStyles();
+ state.root.className = mergeClasses(messageBarTitleClassNames.root, rootBaseStyles, state.root.className);
+
+ return state;
+};
diff --git a/packages/react-components/react-message-bar-preview/src/contexts/messageBarContext.ts b/packages/react-components/react-message-bar-preview/src/contexts/messageBarContext.ts
new file mode 100644
index 0000000000000..add68734a6292
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/src/contexts/messageBarContext.ts
@@ -0,0 +1,13 @@
+import * as React from 'react';
+
+export type MessageBarContextValue = {
+ layout?: 'multiline' | 'singleline';
+};
+const messageBarContext = React.createContext(undefined);
+
+export const messageBarContextDefaultValue: MessageBarContextValue = {
+ layout: 'singleline',
+};
+
+export const MessageBarContextProvider = messageBarContext.Provider;
+export const useMessageBarContext = () => React.useContext(messageBarContext) ?? messageBarContextDefaultValue;
diff --git a/packages/react-components/react-message-bar-preview/src/index.ts b/packages/react-components/react-message-bar-preview/src/index.ts
index cb0ff5c3b541f..e4d035efe8584 100644
--- a/packages/react-components/react-message-bar-preview/src/index.ts
+++ b/packages/react-components/react-message-bar-preview/src/index.ts
@@ -1 +1,42 @@
-export {};
+export {
+ MessageBar,
+ useMessageBarStyles_unstable,
+ useMessageBar_unstable,
+ renderMessageBar_unstable,
+ messageBarClassNames,
+} from './MessageBar';
+
+export type { MessageBarProps, MessageBarSlots, MessageBarState } from './MessageBar';
+
+export {
+ MessageBarTitle,
+ useMessageBarTitleStyles_unstable,
+ useMessageBarTitle_unstable,
+ renderMessageBarTitle_unstable,
+ messageBarTitleClassNames,
+} from './MessageBarTitle';
+
+export type { MessageBarTitleProps, MessageBarTitleSlots, MessageBarTitleState } from './MessageBarTitle';
+
+export {
+ MessageBarActions,
+ useMessageBarActionsStyles_unstable,
+ useMessageBarActions_unstable,
+ renderMessageBarActions_unstable,
+ messageBarActionsClassNames,
+} from './MessageBarActions';
+
+export type { MessageBarActionsProps, MessageBarActionsSlots, MessageBarActionsState } from './MessageBarActions';
+
+export {
+ MessageBarBody,
+ useMessageBarBodyStyles_unstable,
+ useMessageBarBody_unstable,
+ renderMessageBarBody_unstable,
+ messageBarBodyClassNames,
+} from './MessageBarBody';
+
+export type { MessageBarBodyProps, MessageBarBodySlots, MessageBarBodyState } from './MessageBarBody';
+
+export { MessageBarContextProvider, useMessageBarContext } from './contexts/messageBarContext';
+export type { MessageBarContextValue } from './contexts/messageBarContext';
diff --git a/packages/react-components/react-message-bar-preview/stories/MessageBar/Default.stories.tsx b/packages/react-components/react-message-bar-preview/stories/MessageBar/Default.stories.tsx
new file mode 100644
index 0000000000000..c6c7034034318
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/stories/MessageBar/Default.stories.tsx
@@ -0,0 +1,23 @@
+import * as React from 'react';
+import { Button, Link } from '@fluentui/react-components';
+import { DismissRegular } from '@fluentui/react-icons';
+import { MessageBar, MessageBarActions, MessageBarTitle, MessageBarBody } from '@fluentui/react-message-bar-preview';
+
+const intents = ['info', 'warning', 'error', 'success'] as const;
+
+export const Default = () => (
+
+ {intents.map(intent => (
+
+
+ Descriptive title
+ Message providing information to the user with actionable insights. Link
+
+ } />}>
+
+
+
+
+ ))}
+
+);
diff --git a/packages/react-components/react-message-bar-preview/stories/MessageBar/MessageBarBestPractices.md b/packages/react-components/react-message-bar-preview/stories/MessageBar/MessageBarBestPractices.md
new file mode 100644
index 0000000000000..08ff8ddeeb5f8
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/stories/MessageBar/MessageBarBestPractices.md
@@ -0,0 +1,5 @@
+## Best practices
+
+### Do
+
+### Don't
diff --git a/packages/react-components/react-message-bar-preview/stories/MessageBar/MessageBarDescription.md b/packages/react-components/react-message-bar-preview/stories/MessageBar/MessageBarDescription.md
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/packages/react-components/react-message-bar-preview/stories/MessageBar/Multiline.stories.tsx b/packages/react-components/react-message-bar-preview/stories/MessageBar/Multiline.stories.tsx
new file mode 100644
index 0000000000000..87901e5318582
--- /dev/null
+++ b/packages/react-components/react-message-bar-preview/stories/MessageBar/Multiline.stories.tsx
@@ -0,0 +1,23 @@
+import * as React from 'react';
+import { Button, Link } from '@fluentui/react-components';
+import { DismissRegular } from '@fluentui/react-icons';
+import { MessageBar, MessageBarActions, MessageBarBody, MessageBarTitle } from '@fluentui/react-message-bar-preview';
+
+const intents = ['info', 'warning', 'error', 'success'] as const;
+
+export const Multiline = () => (
+
+ {intents.map(intent => (
+
+
+ Descriptive title
+ Message providing information to the user with actionable insights. Link
+
+ } />}>
+
+
+
+
+ ))}
+