diff --git a/site/src/components/Avatar/Avatar.stories.tsx b/site/src/components/Avatar/Avatar.stories.tsx index 256da41bfd..4b6b020dd8 100644 --- a/site/src/components/Avatar/Avatar.stories.tsx +++ b/site/src/components/Avatar/Avatar.stories.tsx @@ -1,4 +1,5 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; +import { expect, waitFor, within } from "storybook/test"; import { Avatar } from "./Avatar"; const meta: Meta = { @@ -74,3 +75,19 @@ export const FallbackSmSize: Story = { fallback: "Adriana Rodrigues", }, }; + +export const WithAlt: Story = { + args: { + variant: "icon", + src: "/icon/code.svg", + alt: "Visual Studio Code template", + }, + play: async ({ canvasElement }) => { + await waitFor(async () => { + const img = await within(canvasElement).findByAltText( + "Visual Studio Code template", + ); + expect(img.tagName).toBe("IMG"); + }); + }, +}; diff --git a/site/src/components/Avatar/Avatar.tsx b/site/src/components/Avatar/Avatar.tsx index 50d7005414..53f83b840c 100644 --- a/site/src/components/Avatar/Avatar.tsx +++ b/site/src/components/Avatar/Avatar.tsx @@ -56,6 +56,12 @@ export type AvatarProps = AvatarPrimitive.AvatarProps & VariantProps & { src?: string; fallback?: string; + /** + * Alt text for the inner ``. Defaults to `""` (decorative, + * hidden from assistive tech). Pass a descriptive value when no + * adjacent text identifies the content. + */ + alt?: string; ref?: React.Ref>; }; @@ -65,6 +71,7 @@ export const Avatar: React.FC = ({ variant, src, fallback, + alt = "", children, ...props }) => { @@ -77,6 +84,7 @@ export const Avatar: React.FC = ({ > diff --git a/site/src/components/Avatar/AvatarData.tsx b/site/src/components/Avatar/AvatarData.tsx index 698e7df608..428825b852 100644 --- a/site/src/components/Avatar/AvatarData.tsx +++ b/site/src/components/Avatar/AvatarData.tsx @@ -17,6 +17,8 @@ interface AvatarDataProps { */ imgFallbackText?: string; + alt?: string; + /** * When true, the title and subtitle clip with an ellipsis if they overflow * the available width. Off by default because callers that pass non-text @@ -31,6 +33,7 @@ export const AvatarData: FC = ({ src, imgFallbackText, avatar, + alt = "", truncate = false, }) => { if (!avatar) { @@ -39,6 +42,7 @@ export const AvatarData: FC = ({ size="lg" src={src} fallback={(typeof title === "string" ? title : imgFallbackText) || "-"} + alt={alt} /> ); } diff --git a/site/src/components/ExternalImage/ExternalImage.tsx b/site/src/components/ExternalImage/ExternalImage.tsx index 46b3c4749d..339cbd6eb3 100644 --- a/site/src/components/ExternalImage/ExternalImage.tsx +++ b/site/src/components/ExternalImage/ExternalImage.tsx @@ -3,13 +3,14 @@ import { getExternalImageStylesFromUrl } from "#/theme/externalImages"; export const ExternalImage: React.FC> = ({ style, + alt = "", ...props }) => { const theme = useTheme(); return ( - // biome-ignore lint/a11y/useAltText: alt should be passed in as a prop {alt} { + await within(canvasElement).findByText(allWorkspaces[0].name); + const images = canvasElement.querySelectorAll("img"); + expect(images.length).toBeGreaterThan(0); + for (const img of images) { + expect(img).toHaveAttribute("alt"); + } + }, }; export const Loading: Story = {