tsimport {XDSThumbnail} from '@xds/core/Thumbnail'
| Guidance | Practices |
|---|---|
| Do | Always provide a label prop with the file name so the thumbnail and its remove button are accessible to screen readers and show a tooltip on hover. |
| Do | Use isLoading without a src to show a skeleton during initial upload, and isLoading with a src to show a spinner overlay once a preview URL is available. |
| Do | Pair onClick with a lightbox or detail view so users can inspect the full image — the thumbnail adds button semantics and a hover shadow automatically. |
| Don't | Don't use Thumbnail for non-image file types like PDFs or spreadsheets — use a file attachment component with an appropriate icon instead. |
| Don't | Don't omit alt text when a src is provided — screen readers need a description of the image content, not just the file name from label. |
tsx'use client';import {XDSThumbnail} from '@xds/core/Thumbnail';import {XDSStack} from '@xds/core/Layout';import {XDSText} from '@xds/core/Text';export default function ThumbnailDisabled() {return (<XDSStack direction="vertical" gap={4}><XDSStack direction="vertical" gap={1}><XDSText type="supporting" color="secondary">Enabled</XDSText><XDSStack direction="horizontal" gap={3} vAlign="center"><XDSThumbnailsrc="https://lookaside.facebook.com/assets/xds_oss/moody-scene-vertical-2.png"alt="Bright landscape"label="landscape.jpg"onRemove={() => {}}/><XDSThumbnail label="document.pdf" onRemove={() => {}} /></XDSStack></XDSStack><XDSStack direction="vertical" gap={1}><XDSText type="supporting" color="secondary">Disabled</XDSText><XDSStack direction="horizontal" gap={3} vAlign="center"><XDSThumbnailsrc="https://lookaside.facebook.com/assets/xds_oss/moody-scene-vertical-2.png"alt="Bright landscape"label="landscape.jpg"onRemove={() => {}}isDisabled/><XDSThumbnail label="document.pdf" onRemove={() => {}} isDisabled /></XDSStack></XDSStack></XDSStack>);}
tsx'use client';import {useState} from 'react';import {XDSThumbnail} from '@xds/core/Thumbnail';import {XDSStack} from '@xds/core/Layout';import {XDSText} from '@xds/core/Text';const ATTACHMENTS = [{id: 1, src: 'https://lookaside.facebook.com/assets/xds_oss/illustrative-vertical-1.jpg', alt: 'River through a valley', label: 'valley.jpg'},{id: 2, src: 'https://lookaside.facebook.com/assets/xds_oss/illustrative-vertical-2.jpg', alt: 'Foggy mountain peak', label: 'mountain.jpg'},{id: 3, src: 'https://lookaside.facebook.com/assets/xds_oss/illustrative-vertical-3.jpg', alt: 'Golden retriever puppy', label: 'puppy.jpg'},{id: 4, src: 'https://lookaside.facebook.com/assets/xds_oss/illustrative-vertical-4.jpg', alt: 'Bridge at sunset', label: 'bridge.jpg'},];export default function ThumbnailGallery() {const [selected, setSelected] = useState<string | null>(null);const [items, setItems] = useState(ATTACHMENTS);return (<XDSStack direction="vertical" gap={3}><XDSText type="supporting" color="secondary">Click to preview, dismiss to remove</XDSText><XDSStack direction="horizontal" gap={2} vAlign="center">{items.map(item => (<XDSThumbnailkey={item.id}src={item.src}alt={item.alt}label={item.label}onClick={() => setSelected(item.label)}onRemove={() =>setItems(prev => prev.filter(i => i.id !== item.id))}/>))}</XDSStack>{selected != null && (<XDSText type="supporting" color="active">Previewing: {selected}</XDSText>)}</XDSStack>);}
tsx'use client';import {useState} from 'react';import {XDSThumbnail} from '@xds/core/Thumbnail';import {XDSStack} from '@xds/core/Layout';import {XDSText} from '@xds/core/Text';const IMAGES = [{id: 1, src: 'https://lookaside.facebook.com/assets/xds_oss/moody-scene-vertical-1.png', alt: 'Dark cityscape at night', label: 'dark-city.jpg'},{id: 2, src: 'https://lookaside.facebook.com/assets/xds_oss/moody-scene-vertical-2.png', alt: 'Bright snowy landscape', label: 'snow.jpg'},{id: 3, src: 'https://lookaside.facebook.com/assets/xds_oss/moody-home-vertical-1.png', alt: 'Warm sunset over mountains', label: 'sunset.jpg'},];export default function ThumbnailRemovable() {const [items, setItems] = useState(IMAGES);return (<XDSStack direction="vertical" gap={4}><XDSText type="supporting" color="secondary">Remove button adapts contrast to image luminance</XDSText><XDSStack direction="horizontal" gap={3} vAlign="center">{items.map(item => (<XDSThumbnailkey={item.id}src={item.src}alt={item.alt}label={item.label}onRemove={() =>setItems(prev => prev.filter(i => i.id !== item.id))}/>))}{items.length === 0 && (<XDSText type="supporting" color="secondary">All removed.</XDSText>)}</XDSStack></XDSStack>);}
tsx'use client';import {XDSThumbnail} from '@xds/core/Thumbnail';import {XDSStack} from '@xds/core/Layout';import {XDSText} from '@xds/core/Text';export default function ThumbnailStates() {return (<XDSStack direction="vertical" gap={4}><XDSStack direction="vertical" gap={1}><XDSText type="supporting" color="secondary">Lifecycle: empty → uploading → processing → loaded</XDSText><XDSStack direction="horizontal" gap={3} vAlign="end"><XDSStack direction="vertical" gap={1} hAlign="center"><XDSThumbnail label="report.pdf" /><XDSText type="supporting" color="secondary">Placeholder</XDSText></XDSStack><XDSStack direction="vertical" gap={1} hAlign="center"><XDSThumbnail isLoading label="uploading.jpg" /><XDSText type="supporting" color="secondary">Skeleton</XDSText></XDSStack><XDSStack direction="vertical" gap={1} hAlign="center"><XDSThumbnailsrc="https://lookaside.facebook.com/assets/xds_oss/moody-home-vertical-1.png"alt="Mountain landscape"isLoadinglabel="landscape.jpg"/><XDSText type="supporting" color="secondary">Uploading</XDSText></XDSStack><XDSStack direction="vertical" gap={1} hAlign="center"><XDSThumbnailsrc="https://lookaside.facebook.com/assets/xds_oss/moody-home-vertical-1.png"alt="Mountain landscape"label="landscape.jpg"/><XDSText type="supporting" color="secondary">Loaded</XDSText></XDSStack></XDSStack></XDSStack></XDSStack>);}
tsx'use client';import {XDSThumbnail} from '@xds/core/Thumbnail';export default function ThumbnailShowcase() {return (<XDSThumbnailsrc="https://lookaside.facebook.com/assets/xds_oss/moody-scene-vertical-2.png"alt="Sample image"label="photo.jpg"/>);}