Overview
Media Object implements the classic media object pattern - a flexible layout for pairing a media element (image, icon, avatar) with content. It consists of three components: MediaObject (the container), MediaFigure (the media element), and MediaBody (the text content).
Use Media Object when you need to:
- Display an icon or image next to text content
- Create notification or alert layouts
- Build comment or message interfaces
- Pair avatars with user information
Installation
npm install @twilio-paste/core
import { MediaObject, MediaFigure, MediaBody } from '@twilio-paste/core/media-object';
// or
import { MediaObject, MediaFigure, MediaBody } from '@twilio-paste/core';
Basic Usage
import { MediaObject, MediaFigure, MediaBody } from '@twilio-paste/core/media-object';
import { Box } from '@twilio-paste/core/box';
import { Text } from '@twilio-paste/core/text';
const MyComponent = () => (
<MediaObject as="div" verticalAlign="center">
<MediaFigure as="div" spacing="space40">
<Box backgroundColor="colorBackgroundSuccess" size="size10" />
</MediaFigure>
<MediaBody as="div">
<Text as="p">We've enabled new security options for your account.</Text>
</MediaBody>
</MediaObject>
);
MediaObject Props
as
keyof JSX.IntrinsicElements
default:"span"
The HTML element to render for the container. Common values: ‘div’, ‘span’, ‘article’.
element
string
default:"MEDIA_OBJECT"
Overrides the default element name to apply unique styles with the Customization Provider.
verticalAlign
'center' | 'top'
default:"top"
Controls vertical alignment of the figure and body.
top - Aligns items to the top (flex-start)
center - Centers items vertically
Sets top margin using space design tokens.
Sets bottom margin using space design tokens.
Should contain MediaFigure and MediaBody components.
MediaFigure Props
as
keyof JSX.IntrinsicElements
default:"span"
The HTML element to render for the figure.
element
string
default:"MEDIA_FIGURE"
Overrides the default element name to apply unique styles with the Customization Provider.
align
'start' | 'end'
default:"start"
Determines which side of the MediaBody the figure appears.
start - Figure appears on the left (adds marginRight)
end - Figure appears on the right (adds marginLeft)
Space between the figure and body. Uses design tokens (e.g., ‘space40’, ‘space60’).
The media content (icon, image, avatar, etc.).
MediaBody Props
as
keyof JSX.IntrinsicElements
default:"span"
The HTML element to render for the body.
element
string
default:"MEDIA_BODY"
Overrides the default element name to apply unique styles with the Customization Provider.
The text or content to display.
Examples
Basic Media Object
import { MediaObject, MediaFigure, MediaBody } from '@twilio-paste/core/media-object';
import { Box } from '@twilio-paste/core/box';
import { Text } from '@twilio-paste/core/text';
const BasicExample = () => (
<MediaObject as="div" verticalAlign="top">
<MediaFigure as="div" spacing="space40">
<Box backgroundColor="colorBackgroundSuccess" height="size10" minWidth="size10" />
</MediaFigure>
<MediaBody as="div">
<Text as="p">We've enabled new security options for your account.</Text>
</MediaBody>
</MediaObject>
);
Centered Alignment
<MediaObject as="div" verticalAlign="center">
<MediaFigure as="div" spacing="space60">
<Box backgroundColor="colorBackgroundPrimary" size="size10" borderRadius="borderRadiusCircle" />
</MediaFigure>
<MediaBody as="div">
<Text as="p">Icon and text are vertically centered.</Text>
</MediaBody>
</MediaObject>
Figure at End
<MediaObject as="div" verticalAlign="center">
<MediaBody as="div">
<Text as="p">Message with action icon on the right.</Text>
</MediaBody>
<MediaFigure as="div" align="end" spacing="space40">
<Box backgroundColor="colorBackgroundError" size="size10" borderRadius="borderRadiusCircle" />
</MediaFigure>
</MediaObject>
Double Figure (Both Sides)
<MediaObject as="div" verticalAlign="center">
<MediaFigure as="div" spacing="space40">
<Box backgroundColor="colorBackgroundSuccess" height="size10" minWidth="size10" />
</MediaFigure>
<MediaBody as="div">
<Text as="p">Please update your billing information or we'll suspend your account on March 2.</Text>
</MediaBody>
<MediaFigure as="div" align="end" spacing="space40">
<Box backgroundColor="colorBackgroundWarning" height="size10" minWidth="size10" />
</MediaFigure>
</MediaObject>
With Icon
import { MediaObject, MediaFigure, MediaBody } from '@twilio-paste/core/media-object';
import { InformationIcon } from '@twilio-paste/icons/esm/InformationIcon';
import { Text } from '@twilio-paste/core/text';
const WithIcon = () => (
<MediaObject as="div" verticalAlign="center">
<MediaFigure as="div" spacing="space30">
<InformationIcon decorative color="colorIconInformation" size="sizeIcon40" />
</MediaFigure>
<MediaBody as="div">
<Text as="p">Your changes have been saved successfully.</Text>
</MediaBody>
</MediaObject>
);
With Avatar
import { MediaObject, MediaFigure, MediaBody } from '@twilio-paste/core/media-object';
import { Avatar } from '@twilio-paste/core/avatar';
import { Text } from '@twilio-paste/core/text';
import { Heading } from '@twilio-paste/core/heading';
import { Stack } from '@twilio-paste/core/stack';
const UserComment = () => (
<MediaObject as="div" verticalAlign="top">
<MediaFigure as="div" spacing="space40">
<Avatar size="sizeIcon70" name="Jane Doe" />
</MediaFigure>
<MediaBody as="div">
<Stack orientation="vertical" spacing="space20">
<Heading as="h3" variant="heading50">Jane Doe</Heading>
<Text as="p">This is a great feature! Thanks for building it.</Text>
</Stack>
</MediaBody>
</MediaObject>
);
Notification Layout
import { MediaObject, MediaFigure, MediaBody } from '@twilio-paste/core/media-object';
import { Box } from '@twilio-paste/core/box';
import { Text } from '@twilio-paste/core/text';
import { Heading } from '@twilio-paste/core/heading';
import { Stack } from '@twilio-paste/core/stack';
const Notification = () => (
<Box
padding="space60"
backgroundColor="colorBackgroundSuccessWeakest"
borderRadius="borderRadius20"
>
<MediaObject as="div" verticalAlign="top">
<MediaFigure as="div" spacing="space40">
<Box
backgroundColor="colorBackgroundSuccess"
size="size10"
borderRadius="borderRadiusCircle"
/>
</MediaFigure>
<MediaBody as="div">
<Stack orientation="vertical" spacing="space20">
<Heading as="h3" variant="heading40">Success!</Heading>
<Text as="p">Your payment has been processed.</Text>
</Stack>
</MediaBody>
</MediaObject>
</Box>
);
Constrained Width with Text Overflow
import { MediaObject, MediaFigure, MediaBody } from '@twilio-paste/core/media-object';
import { Box } from '@twilio-paste/core/box';
import { Text } from '@twilio-paste/core/text';
import { Truncate } from '@twilio-paste/core/truncate';
const ConstrainedWidth = () => (
<Box width="size60">
<MediaObject as="div" verticalAlign="center">
<MediaFigure as="div" spacing="space100">
<Box backgroundColor="colorBackgroundSuccess" size="size20" />
</MediaFigure>
<MediaBody as="div">
<Text as="p">You can now set up your contact preferences on your dashboard.</Text>
<Text as="p">
<Truncate title="http://www.extremelylongurlthatmightbreakthelayout.com">
http://www.extremelylongurlthatmightbreakthelayout.com
</Truncate>
</Text>
</MediaBody>
<MediaFigure as="div" align="end" spacing="space70">
<Box backgroundColor="colorBackgroundWarning" height="size10" minWidth="size10" />
</MediaFigure>
</MediaObject>
</Box>
);
List of Media Objects
import { MediaObject, MediaFigure, MediaBody } from '@twilio-paste/core/media-object';
import { Stack } from '@twilio-paste/core/stack';
import { Box } from '@twilio-paste/core/box';
import { Text } from '@twilio-paste/core/text';
const NotificationList = () => (
<Stack orientation="vertical" spacing="space60">
<MediaObject as="div" verticalAlign="center">
<MediaFigure as="div" spacing="space40">
<Box backgroundColor="colorBackgroundSuccess" size="size10" />
</MediaFigure>
<MediaBody as="div">
<Text as="p">First notification message</Text>
</MediaBody>
</MediaObject>
<MediaObject as="div" verticalAlign="center">
<MediaFigure as="div" spacing="space40">
<Box backgroundColor="colorBackgroundWarning" size="size10" />
</MediaFigure>
<MediaBody as="div">
<Text as="p">Second notification message</Text>
</MediaBody>
</MediaObject>
<MediaObject as="div" verticalAlign="center">
<MediaFigure as="div" spacing="space40">
<Box backgroundColor="colorBackgroundError" size="size10" />
</MediaFigure>
<MediaBody as="div">
<Text as="p">Third notification message</Text>
</MediaBody>
</MediaObject>
</Stack>
);
How It Works
The Media Object layout uses flexbox:
- MediaObject: Sets
display: flex and controls alignment
- MediaFigure: Sets
flexShrink: 0 so it never shrinks, and adds spacing via margin
- MediaBody: Sets
flex: 1 and minWidth: size0 so it grows to fill space and can shrink with text wrapping
This ensures the figure maintains its size while the body flexes and wraps as needed.
Best Practices
Use Appropriate Spacing
Match spacing to the size of your media element:
// Small icons - tighter spacing
<MediaFigure spacing="space30">
<Icon size="sizeIcon20" />
</MediaFigure>
// Large images/avatars - more spacing
<MediaFigure spacing="space60">
<Avatar size="sizeIcon90" />
</MediaFigure>
Choose the Right Alignment
Use alignment based on content:
// Top alignment for multi-line content
<MediaObject verticalAlign="top">
<MediaFigure spacing="space40">
<Avatar />
</MediaFigure>
<MediaBody>
<Heading>Name</Heading>
<Paragraph>Long bio text...</Paragraph>
</MediaBody>
</MediaObject>
// Center alignment for single-line content
<MediaObject verticalAlign="center">
<MediaFigure spacing="space30">
<Icon />
</MediaFigure>
<MediaBody>
<Text>Short message</Text>
</MediaBody>
</MediaObject>
Use Semantic HTML
Choose appropriate elements via the as prop:
// Article/comment
<MediaObject as="article">
<MediaFigure as="div">...</MediaFigure>
<MediaBody as="div">...</MediaBody>
</MediaObject>
// Inline notification
<MediaObject as="span">
<MediaFigure as="span">...</MediaFigure>
<MediaBody as="span">...</MediaBody>
</MediaObject>
Constrain Width When Needed
Wrap in a Box with width constraints to control layout:
<Box maxWidth="size70">
<MediaObject as="div">
<MediaFigure spacing="space40">...</MediaFigure>
<MediaBody>...</MediaBody>
</MediaObject>
</Box>
Don’t Nest Media Figures
Use one or two MediaFigure components per MediaObject (start and/or end), not nested figures:
// Good
<MediaObject>
<MediaFigure align="start">...</MediaFigure>
<MediaBody>...</MediaBody>
<MediaFigure align="end">...</MediaFigure>
</MediaObject>
// Avoid
<MediaObject>
<MediaFigure>
<MediaFigure>...</MediaFigure>
</MediaFigure>
<MediaBody>...</MediaBody>
</MediaObject>
Accessibility
- Use semantic HTML elements via the
as prop when appropriate
- MediaObject itself is purely presentational
- Ensure any icons in MediaFigure have appropriate
decorative or title props
- Don’t rely solely on icon color to convey meaning
- Ensure text content in MediaBody has sufficient color contrast
- When using for interactive items (like comments), consider wrapping in appropriate interactive elements
Related Components
- Box - Low-level layout primitive
- Flex - Flexbox layouts
- Stack - Vertical or horizontal stacking
- Avatar - User avatar component
- Icon - Icon components