Default

Loading interactive example. Full source is available below.

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

import { Card } from "@coreai-ds/react-components";
import { CardHeader } from "@coreai-ds/react-components";
import { Text } from "@coreai-ds/react-components";
import { CardPreview } from "@coreai-ds/react-components";
import { CardFooter } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { ArrowReplyRegular } from "@fluentui/react-icons";
import { ShareRegular } from "@fluentui/react-icons";
import * as React from 'react';

export const Default = () => {
    const resolveAsset = (asset: string) => {
        const assetUrl = 'https://raw.githubusercontent.com/microsoft/fluentui/master/packages/react-components/react-card/stories/src/assets/';
        return `${assetUrl}${asset}`;
    };
    const styles = /* css */ `
      .card-default-example {
        margin: auto;
        max-width: 720px;
        width: 100%;
      }
    `;
    return (<>
        <style>{styles}</style>
        <Card className="card-default-example">
          <CardHeader image={<img src={resolveAsset('avatar_elvia.svg')} alt="Elvia Atkins avatar picture"/>} header={<Text preset="body">
                <b>Elvia Atkins</b> mentioned you
              </Text>} description={<Text preset="bodyS">5h ago · About us - Overview</Text>}/>

          <CardPreview logo={<img src={resolveAsset('docx.png')} alt="Microsoft Word document"/>}>
            <img src={resolveAsset('doc_template.png')} alt="Preview of a Word document: About Us - Overview"/>
          </CardPreview>

          <CardFooter>
            <Button icon={<ArrowReplyRegular fontSize={16}/>}>Reply</Button>
            <Button icon={<ShareRegular fontSize={16}/>}>Share</Button>
          </CardFooter>
        </Card>
      </>);
};

export default Default;

Resources

Behavior and states

  • When there are multiple available actions, a card can hold buttons and links.
  • If there is one obvious action, the entire card surface can function as a button.
  • Cards can also be used to let people make a selection, similar to checkboxes or radio groups.
  • By default, there is no indicator on cards that signifies they are selectable, but interaction states like hover and focus can hint at selectability.
  • While they’re very flexible, it’s important to use them consistently for particular use cases across experiences.

For React Router navigation, see the Card Link template. Prefer an existing repository adapter when your app already provides one.

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.

Card API

interface CardProps {
  /**
   * Sets the appearance of the card.
   *
   * `filled`
   * The card will have a shadow, border and background color.
   *
   * `filled-alternative`
   * This appearance is similar to `filled`, but the background color will be a little darker.
   *
   * `outline`
   * This appearance is similar to `filled`, but the background color will be transparent and no shadow applied.
   *
   * `subtle`
   * This appearance is similar to `filled-alternative`, but no border is applied.
   * @default 'filled'
   */
  appearance?: "filled" | "outline" | "subtle" | "filled-alternative";

  as?: "div";

  /**
   * The internal checkbox element that renders when the card is selectable.
   */
  checkbox?: ({ as?: "input"; } & Omit<Omit<DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref"> & { ref?: ((instance: HTMLInputElement | null) => void) | RefObject<HTMLInputElement> | null; }, "children"> & { children?: undefined; }) | null | undefined;

  children?: any;

  className?: string;

  /**
   * Defines whether the card is initially in a selected state when rendered.
   * @default false
   */
  defaultSelected?: boolean;

  /**
   * Makes the card and card selection disabled (not propagated to children).
   * @default false
   */
  disabled?: boolean;

  /**
   * Floating action that can be rendered on the top-right of a card. Often used together with
   * `selected`, `defaultSelected`, and `onSelectionChange` props
   */
  floatingAction?: WithSlotShorthandValue<{ as?: "div"; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & { ref?: ((instance: HTMLDivElement | null) => void) | RefObject<HTMLDivElement> | null; }, "children"> & { children?: any; }> | null | undefined;

  /**
   * Placement of the `floatingAction` slot within the card.
   * - 'right' (default): matches stock Fluent placement
   * - 'left': left edge
   * @default 'right'
   */
  floatingActionPosition?: "right" | "left";

  /**
   * Sets the focus behavior for the card.
   *
   * `off`
   * The card will not focusable.
   *
   * `no-tab`
   * This behaviour traps the focus inside of the Card when pressing the Enter key and will only release focus when
   * pressing the Escape key.
   *
   * `tab-exit`
   * This behaviour traps the focus inside of the Card when pressing the Enter key but will release focus when pressing
   * the Tab key on the last inner element.
   *
   * `tab-only`
   * This behaviour will cycle through all elements inside of the Card when pressing the Tab key and then release focus
   * after the last inner element.
   * @default 'off'
   */
  focusMode?: "off" | "no-tab" | "tab-exit" | "tab-only";

  /**
   * Callback to be called when the selected state value changes.
   */
  onSelectionChange?: ((event: CardOnSelectionChangeEvent, data: CardOnSelectData) => void);

  /**
   * Defines the orientation of the card.
   * @default 'vertical'
   */
  orientation?: "horizontal" | "vertical";

  ref?: Ref<HTMLDivElement>;

  /**
   * Defines the controlled selected state of the card.
   * @default false
   */
  selected?: boolean;

  /**
   * Controls the card's border radius and padding between inner elements.
   * @default 'medium'
   */
  size?: "small" | "medium" | "large";

  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.

Appearance

Loading interactive example. Full source is available below.

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

import { Text } from "@coreai-ds/react-components";
import type { CardProps } from "@coreai-ds/react-components";
import * as React from 'react';
import { Card } from "@coreai-ds/react-components";
import { CardHeader } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { MoreHorizontal20Regular } from "@fluentui/react-icons";

export const Appearance = () => {
    const resolveAsset = (asset: string) => {
        const assetUrl = 'https://raw.githubusercontent.com/microsoft/fluentui/master/packages/react-components/react-card/stories/src/assets/';
        return `${assetUrl}${asset}`;
    };
    const ExampleHeader = ({ title, description }: Record<string, string>) => (<header>
        {title ? (<Text as="h4" preset="heading3" block className="card-appearance-example__title">
            {title}
          </Text>) : null}
        {description ? (<Text as="p" preset="body" block className="card-appearance-example__description">
            {description}
          </Text>) : null}
      </header>);
    const CardExample = (props: CardProps) => {
        const onClick = React.useCallback(() => console.log('Interactive!'), []);
        return (<Card {...props} className="card-appearance-example__card" onClick={onClick}>
          <CardHeader image={<img className="card-appearance-example__logo" src={resolveAsset('app_logo.svg')} alt="App name logo"/>} header={<Text as="h5" className="card-appearance-example__app-name" weight="semibold">
                App Name
              </Text>} description={<Text preset="bodyS" className="card-appearance-example__caption">
                Developer
              </Text>} action={<Button appearance="transparent" icon={<MoreHorizontal20Regular />} aria-label="More options"/>}/>
          <p className="card-appearance-example__text">
            Donut chocolate bar oat cake. Dragée tiramisu lollipop bear claw. Marshmallow pastry
            jujubes toffee sugar plum.
          </p>
        </Card>);
    };
    const styles = /* css */ `
      .card-appearance-example {
        display: flex;
        flex-direction: column;
        flex-wrap: wrap;
        gap: 36px;
      }

      .card-appearance-example__title,
      .card-appearance-example__description {
        margin: 0 0 var(--spacingVerticalM);
      }

      .card-appearance-example__card {
        height: fit-content;
        max-width: 480px;
        width: 100%;
      }

      .card-appearance-example__caption {
        color: var(--colorNeutralForeground3);
      }

      .card-appearance-example__logo {
        border-radius: var(--borderRadiusMedium);
        height: 48px;
        width: 48px;
      }

      .card-appearance-example__app-name,
      .card-appearance-example__text {
        margin: 0;
      }

      .card-appearance-example__filled-section {
        background-color: var(--colorNeutralBackground3);
        margin-inline: -48px;
        padding-block: var(--spacingVerticalXL);
        padding-inline: 48px;
      }
    `;
    return (<>
        <style>{styles}</style>
        <div className="card-appearance-example">
          <section>
            <ExampleHeader title="Filled Alternative (CoreAI Default)" description="Under the CoreAI theme, Card defaults to `filled-alternative`. Use this for most card
              designs when displayed on a lighter gray or white surface to ensure adequate contrast between the card
              surface and the application background."/>
            <CardExample appearance="filled-alternative"/>
          </section>

          <section className="card-appearance-example__filled-section">
            <ExampleHeader title="Filled (on colorNeutralBackground3)" description="The stock Fluent default style. Explicitly opt in to `filled` when you want the original
              filled treatment instead of the CoreAI default."/>
            <CardExample appearance="filled"/>
          </section>

          <section>
            <ExampleHeader title="Outline" description="Use when you don't want a filled background color but a discernable outline (border) on the
              card."/>
            <CardExample appearance="outline"/>
          </section>

          <section>
            <ExampleHeader title="Subtle" description="This variant doesn't have a background or border for the card container. However, it does include
              interaction states that display a visible footprint when interacting with the card item."/>
            <CardExample appearance="subtle"/>
          </section>
        </div>
      </>);
};

export default Appearance;

Disabled

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 * as React from 'react';
import { Card } from "@coreai-ds/react-components";
import { CardHeader } from "@coreai-ds/react-components";
import { Body1 } from "@coreai-ds/react-components";
import { Caption1 } from "@coreai-ds/react-components";
import { CardPreview } from "@coreai-ds/react-components";
import { CardFooter } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { ArrowReplyRegular } from "@fluentui/react-icons";
import { ShareRegular } from "@fluentui/react-icons";
import { Checkbox } from "@coreai-ds/react-components";

const useStyles = makeStyles({
    container: {
        display: 'flex',
        flexDirection: 'column',
        gap: '16px',
    },
    card: {
        maxWidth: '400px',
        minWidth: '230px',
        width: '100%',
    },
});

const resolveAsset = (asset: string) => {
    const ASSET_URL = 'https://raw.githubusercontent.com/microsoft/fluentui/master/packages/react-components/react-card/stories/src/assets/';
    return `${ASSET_URL}${asset}`;
};

const CardContentExample = ({ disabled }: {
    disabled?: boolean;
}) => (<>
    <CardHeader image={<img src={resolveAsset('avatar_elvia.svg')} alt="Elvia Atkins avatar picture"/>} header={<Body1>
          <b>Elvia Atkins</b> mentioned you
        </Body1>} description={<Caption1>5h ago · About us - Overview</Caption1>}/>

    <CardPreview logo={<img src={resolveAsset('docx.png')} alt="Microsoft Word document"/>}>
      <img src={resolveAsset('doc_template.png')} alt="Preview of a Word document: About Us - Overview"/>
    </CardPreview>

    <CardFooter>
      <Button disabled={disabled} icon={<ArrowReplyRegular fontSize={16}/>}>
        Reply
      </Button>
      <Button disabled={disabled} icon={<ShareRegular fontSize={16}/>}>
        Share
      </Button>
    </CardFooter>
  </>);

export const Disabled = (): JSXElement => {
    const styles = useStyles();
    const [isSelected1, setIsSelected1] = React.useState(false);
    const [isSelected2, setIsSelected2] = React.useState(false);
    return (<div className={styles.container}>
      <div>
        <h3>Default Card</h3>
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: '16px' }}>
          <Card className={styles.card}>
            <CardContentExample />
          </Card>

          <Card className={styles.card} disabled>
            <CardContentExample disabled/>
          </Card>
        </div>
      </div>

      <div>
        <h3>Interactive Card</h3>
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: '16px' }}>
          <Card className={styles.card} onClick={() => alert('Card clicked')}>
            <CardContentExample />
          </Card>

          <Card className={styles.card} disabled onClick={() => alert('Card clicked')}>
            <CardContentExample disabled/>
          </Card>
        </div>
      </div>

      <div>
        <h3>Selectable Card</h3>
        <div style={{ display: 'flex', flexDirection: 'column', rowGap: '16px' }}>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: '16px' }}>
            <Card className={styles.card} selected={isSelected1} onSelectionChange={(_, { selected }) => setIsSelected1(selected)}>
              <CardContentExample />
            </Card>
            <Card className={styles.card} disabled selected={false}>
              <CardContentExample disabled/>
            </Card>
          </div>

          <div style={{ display: 'flex', flexWrap: 'wrap', gap: '16px' }}>
            <Card className={styles.card} selected={isSelected2} onSelectionChange={(_, { selected }) => setIsSelected2(selected)} floatingAction={<Checkbox checked={isSelected2} onChange={() => setIsSelected2(!isSelected2)}/>}>
              <CardContentExample />
            </Card>
            <Card className={styles.card} selected={false} floatingAction={<Checkbox disabled/>} disabled>
              <CardContentExample disabled/>
            </Card>
          </div>
        </div>
      </div>

      <div>
        <h3>Outline Card</h3>
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: '16px' }}>
          <Card className={styles.card} appearance="outline">
            <CardContentExample />
          </Card>

          <Card className={styles.card} appearance="outline" disabled>
            <CardContentExample disabled/>
          </Card>
        </div>
      </div>
    </div>);
};

export default Disabled;

Floating Action Position

Loading interactive example. Full source is available below.

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

import type { CardFloatingActionPosition } from "@coreai-ds/react-components";
import * as React from 'react';
import { Card } from "@coreai-ds/react-components";
import { Checkbox } from "@coreai-ds/react-components";
import { CardHeader } from "@coreai-ds/react-components";
import { Text } from "@coreai-ds/react-components";

export const FloatingActionPosition = () => {
    const positions: {
        value: CardFloatingActionPosition;
        label: string;
    }[] = [
        { value: 'right', label: 'Right (default)' },
        { value: 'left', label: 'Left' },
    ];
    const PositionCard = ({ position, label, }: {
        position: CardFloatingActionPosition;
        label: string;
    }) => {
        const [selected, setSelected] = React.useState(false);
        return (<Card className="card-floating-action-example__card" floatingActionPosition={position} floatingAction={<Checkbox checked={selected} aria-label={`Select ${label}`} onChange={(_, data) => setSelected(!!data.checked)}/>} selected={selected} onSelectionChange={(_, data) => setSelected(data.selected)}>
          <CardHeader header={<Text weight="semibold">{label}</Text>} description={<Text preset="bodyS" className="card-floating-action-example__caption">
                floatingActionPosition="{position}"
              </Text>}/>
        </Card>);
    };
    const styles = /* css */ `
      .card-floating-action-example {
        display: flex;
        flex-direction: column;
        flex-wrap: wrap;
        gap: 36px;
      }

      .card-floating-action-example__title {
        margin: 0 0 var(--spacingVerticalM);
      }

      .card-floating-action-example__grid {
        display: flex;
        gap: var(--spacingHorizontalL);
      }

      .card-floating-action-example__card {
        height: fit-content;
      }

      .card-floating-action-example__caption {
        color: var(--colorNeutralForeground3);
      }
    `;
    return (<>
        <style>{styles}</style>
        <div className="card-floating-action-example">
          <header>
            <Text as="h4" preset="heading3" block className="card-floating-action-example__title">
              Floating action position
            </Text>
            <Text as="p" preset="body" block>
              The CoreAI <code>Card</code> adds a <code>floatingActionPosition</code> prop that
              re-pins the <code>floatingAction</code> slot. Stock Fluent only supports the right
              placement; the wrapper adds a left placement.
            </Text>
          </header>

          <div className="card-floating-action-example__grid">
            {positions.map(({ value, label }) => (<PositionCard key={value} position={value} label={label}/>))}
          </div>
        </div>
      </>);
};

export default FloatingActionPosition;

Focus Mode

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 { Subtitle1 } from "@coreai-ds/react-components";
import { Body1 } from "@coreai-ds/react-components";
import type { CardProps } from "@coreai-ds/react-components";
import { Card } from "@coreai-ds/react-components";
import { CardPreview } from "@coreai-ds/react-components";
import { CardHeader } from "@coreai-ds/react-components";
import { Caption1 } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { MoreHorizontal20Regular } from "@fluentui/react-icons";
import { CardFooter } from "@coreai-ds/react-components";
import { Open16Regular } from "@fluentui/react-icons";
import { Share16Regular } from "@fluentui/react-icons";
import * as React from 'react';

const useStyles = makeStyles({
    main: {
        display: 'flex',
        flexWrap: 'wrap',
        flexDirection: 'column',
        columnGap: '16px',
        rowGap: '36px',
    },
    title: { margin: '0 0 12px' },
    description: { margin: '0 0 12px' },
    card: {
        maxWidth: '400px',
        width: '100%',
        height: 'fit-content',
    },
    text: { margin: '0' },
});

const Header = ({ title, description }: Record<string, string>) => {
    const styles = useStyles();
    return (<>
      {title ? (<Subtitle1 as="h4" block className={styles.title}>
          {title}
        </Subtitle1>) : null}

      {description ? (<Body1 as="p" block className={styles.description}>
          {description}
        </Body1>) : null}
    </>);
};

const resolveAsset = (asset: string) => {
    const ASSET_URL = 'https://raw.githubusercontent.com/microsoft/fluentui/master/packages/react-components/react-card/stories/src/assets/';
    return `${ASSET_URL}${asset}`;
};

const CardExample = (props: CardProps) => {
    const styles = useStyles();
    return (<Card className={styles.card} {...props}>
      <CardPreview>
        <img src={resolveAsset('sales_template.png')} alt="Sales Presentation Preview"/>
      </CardPreview>

      <CardHeader image={<img src={resolveAsset('pptx.png')} width="32px" height="32px" alt="Microsoft PowerPoint logo"/>} header={<Body1 as="h5" style={{ margin: 0, fontWeight: 'bold' }}>
            App Name
          </Body1>} description={<Caption1>Developer</Caption1>} action={<Button appearance="transparent" icon={<MoreHorizontal20Regular />} aria-label="More options"/>}/>

      <p className={styles.text}>
        Donut chocolate bar oat cake. Dragée tiramisu lollipop bear claw. Marshmallow pastry jujubes toffee sugar plum.
      </p>

      <CardFooter>
        <Button appearance="primary" icon={<Open16Regular />}>
          Open
        </Button>
        <Button icon={<Share16Regular />}>Share</Button>
      </CardFooter>
    </Card>);
};

export const FocusMode = (): JSXElement => {
    const styles = useStyles();
    return (<div className={styles.main}>
      <section>
        <Header title="'off' (Default)" description="The contents might still be focusable, but the Card won't manage the focus of its contents or be
          focusable."/>
        <CardExample />
      </section>

      <section>
        <Header title="'no-tab'" description="The Card will be focusable and trap the focus. You can use Tab to navigate between the contents
          and escaping focus only by pressing the Esc key."/>
        <CardExample focusMode="no-tab"/>
      </section>

      <section>
        <Header title="'tab-exit'" description="The Card will be focusable and trap the focus, but release it on an Esc or Tab key press."/>
        <CardExample focusMode="tab-exit"/>
      </section>

      <section>
        <Header title="'tab-only'" description="The Card will not trap focus but will still be focusable and allow Tab navigation of its
          contents."/>
        <CardExample focusMode="tab-only"/>
      </section>
    </div>);
};

export default FocusMode;

Orientation

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 { Subtitle1 } from "@coreai-ds/react-components";
import { Card } from "@coreai-ds/react-components";
import { CardHeader } from "@coreai-ds/react-components";
import { Text } from "@coreai-ds/react-components";
import { Caption1 } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { MoreHorizontal20Regular } from "@fluentui/react-icons";
import { CardPreview } from "@coreai-ds/react-components";

const useStyles = makeStyles({
    main: {
        gap: '36px',
        display: 'flex',
        flexDirection: 'column',
        flexWrap: 'wrap',
    },
    card: {
        width: '100%',
        height: 'fit-content',
    },
    section: {
        maxWidth: '360px',
        width: '100%',
    },
    title: { margin: '0 0 12px' },
    horizontalCardImage: {
        width: '64px',
        height: '64px',
    },
    headerImage: {
        borderRadius: '4px',
        maxWidth: '44px',
        maxHeight: '44px',
    },
    caption: {
        color: tokens.colorNeutralForeground3,
    },
    text: { margin: '0' },
});

const Title = ({ children }: React.PropsWithChildren<{}>) => {
    const styles = useStyles();
    return (<Subtitle1 as="h4" block className={styles.title}>
      {children}
    </Subtitle1>);
};

const resolveAsset = (asset: string) => {
    const ASSET_URL = 'https://raw.githubusercontent.com/microsoft/fluentui/master/packages/react-components/react-card/stories/src/assets/';
    return `${ASSET_URL}${asset}`;
};

export const Orientation = (): JSXElement => {
    const styles = useStyles();
    return (<div className={styles.main}>
      <section className={styles.section}>
        <Title>'vertical' (Default)</Title>
        <p>With image as part of header</p>

        <Card className={styles.card}>
          <CardHeader image={<img className={styles.headerImage} src={resolveAsset('app_logo.svg')} alt="App Name Document"/>} header={<Text as="h5" weight="semibold" style={{ margin: 0 }}>
                App Name
              </Text>} description={<Caption1 className={styles.caption}>Developer</Caption1>} action={<Button appearance="transparent" icon={<MoreHorizontal20Regular />} aria-label="More options"/>}/>

          <p className={styles.text}>
            Donut chocolate bar oat cake. Dragée tiramisu lollipop bear claw. Marshmallow pastry jujubes toffee sugar
            plum.
          </p>
        </Card>
      </section>

      <section className={styles.section}>
        <Title>'horizontal'</Title>
        <p>With image as part of preview</p>

        <Card className={styles.card} orientation="horizontal">
          <CardPreview className={styles.horizontalCardImage}>
            <img className={styles.horizontalCardImage} src={resolveAsset('app_logo.svg')} alt="App Name Document"/>
          </CardPreview>

          <CardHeader header={<Text weight="semibold">App Name</Text>} description={<Caption1 className={styles.caption}>Developer</Caption1>} action={<Button appearance="transparent" icon={<MoreHorizontal20Regular />} aria-label="More options"/>}/>
        </Card>
      </section>
    </div>);
};

export default Orientation;

Outline Interactivity

Loading interactive example. Full source is available below.

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

import * as React from 'react';
import { Card } from "@coreai-ds/react-components";
import { CardHeader } from "@coreai-ds/react-components";
import { Text } from "@coreai-ds/react-components";
import { Checkbox } from "@coreai-ds/react-components";

// ---------- OutlineInteractivity ----------
export const OutlineInteractivity = () => {
    const [selected, setSelected] = React.useState(false);
    const styles = /* css */ `
    .card-outline-interactivity-example {
      display: flex;
      flex-direction: column;
      gap: 36px;
    }

    .card-outline-interactivity-example__card {
      width: 100%;
      max-width: 480px;
      height: fit-content;
    }

    .card-outline-interactivity-example__caption {
      color: var(--colorNeutralForeground3);
    }
  `;
    return (<>
      <style>{styles}</style>
      <div className="card-outline-interactivity-example">
        {/* Static — no hover/active feedback */}
        <Card appearance="outline" className="card-outline-interactivity-example__card">
          <CardHeader header={<Text weight="semibold">Static</Text>} description={<Text preset="bodyS" className="card-outline-interactivity-example__caption">
                No onClick, no selection — remains visually inert on hover.
              </Text>}/>
        </Card>

        {/* Interactive — hover/active feedback */}
        <Card appearance="outline" className="card-outline-interactivity-example__card" onClick={() => console.log('clicked')}>
          <CardHeader header={<Text weight="semibold">Interactive</Text>} description={<Text preset="bodyS" className="card-outline-interactivity-example__caption">
                Has onClick — shows hover and pressed background.
              </Text>}/>
        </Card>

        {/* Selectable — hover/active feedback */}
        <Card appearance="outline" className="card-outline-interactivity-example__card" floatingAction={<Checkbox checked={selected} onChange={(_, data) => setSelected(!!data.checked)} aria-label="Select card"/>} selected={selected} onSelectionChange={(_, data) => setSelected(data.selected)}>
          <CardHeader header={<Text weight="semibold">Selectable</Text>} description={<Text preset="bodyS" className="card-outline-interactivity-example__caption">
                Has selection — shows hover and pressed background.
              </Text>}/>
        </Card>

        {/* Disabled — no hover/active feedback */}
        <Card appearance="outline" className="card-outline-interactivity-example__card" onClick={() => console.log('clicked')} disabled>
          <CardHeader header={<Text weight="semibold">Disabled</Text>} description={<Text preset="bodyS" className="card-outline-interactivity-example__caption">
                Has onClick but disabled — remains visually static.
              </Text>}/>
        </Card>
      </div>
    </>);
};

export default OutlineInteractivity;

Selectable

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 { CardProps } from "@coreai-ds/react-components";
import { Card } from "@coreai-ds/react-components";
import { CardPreview } from "@coreai-ds/react-components";
import { CardHeader } from "@coreai-ds/react-components";
import { Text } from "@coreai-ds/react-components";
import { Caption1 } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { MoreHorizontal20Regular } from "@fluentui/react-icons";

const useStyles = makeStyles({
    main: {
        gap: '16px',
        display: 'flex',
        flexWrap: 'wrap',
    },
    card: {
        maxWidth: '400px',
        width: '100%',
        height: 'fit-content',
    },
    caption: {
        color: tokens.colorNeutralForeground3,
    },
    smallRadius: { borderRadius: tokens.borderRadiusSmall },
    grayBackground: {
        backgroundColor: tokens.colorNeutralBackground3,
    },
    logoBadge: {
        padding: '5px',
        borderRadius: tokens.borderRadiusSmall,
        backgroundColor: '#FFF',
        boxShadow: '0px 1px 2px rgba(0, 0, 0, 0.14), 0px 0px 2px rgba(0, 0, 0, 0.12)',
    },
});

const resolveAsset = (asset: string) => {
    const ASSET_URL = 'https://raw.githubusercontent.com/microsoft/fluentui/master/packages/react-components/react-card/stories/src/assets/';
    return `${ASSET_URL}${asset}`;
};

const CardExample = (props: CardProps) => {
    const styles = useStyles();
    return (<Card className={styles.card} {...props}>
      <CardPreview className={styles.grayBackground} logo={<img className={styles.logoBadge} src={resolveAsset('logo3.svg')} alt="Figma app logo"/>}>
        <img className={styles.smallRadius} src={resolveAsset('office1.png')} alt="Presentation Preview"/>
      </CardPreview>

      <CardHeader header={<Text weight="semibold">iOS App Prototype</Text>} description={<Caption1 className={styles.caption}>You created 53m ago</Caption1>} action={<Button appearance="transparent" icon={<MoreHorizontal20Regular />} aria-label="More actions"/>}/>
    </Card>);
};

export const Selectable = (): JSXElement => {
    const styles = useStyles();
    const [selected1, setSelected1] = React.useState(false);
    const [selected2, setSelected2] = React.useState(false);
    return (<div className={styles.main}>
      <CardExample selected={selected1} onSelectionChange={(_, { selected }) => setSelected1(selected)}/>
      <CardExample selected={selected2} onSelectionChange={(_, { selected }) => setSelected2(selected)}/>
    </div>);
};

export default Selectable;

Selectable Indicator

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 { useId } from "@coreai-ds/react-components";
import * as React from 'react';
import { Card } from "@coreai-ds/react-components";
import { Checkbox } from "@coreai-ds/react-components";
import { CardPreview } from "@coreai-ds/react-components";
import { CardHeader } from "@coreai-ds/react-components";
import { Text } from "@coreai-ds/react-components";
import { Caption1 } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { MoreHorizontal20Regular } from "@fluentui/react-icons";

const flex = {
    gap: '16px',
    display: 'flex',
};

const useStyles = makeStyles({
    main: {
        ...flex,
        flexDirection: 'column',
    },
    row: {
        ...flex,
        flexWrap: 'wrap',
    },
    card: {
        maxWidth: '400px',
        width: '100%',
        height: 'fit-content',
    },
    caption: {
        color: tokens.colorNeutralForeground3,
    },
    smallRadius: { borderRadius: tokens.borderRadiusSmall },
    grayBackground: {
        backgroundColor: tokens.colorNeutralBackground3,
    },
    logoBadge: {
        padding: '5px',
        borderRadius: tokens.borderRadiusSmall,
        backgroundColor: '#FFF',
        boxShadow: '0px 1px 2px rgba(0, 0, 0, 0.14), 0px 0px 2px rgba(0, 0, 0, 0.12)',
    },
    actions: {
        display: 'flex',
    },
});

const resolveAsset = (asset: string) => {
    const ASSET_URL = 'https://raw.githubusercontent.com/microsoft/fluentui/master/packages/react-components/react-card/stories/src/assets/';
    return `${ASSET_URL}${asset}`;
};

export const SelectableIndicator = (): JSXElement => {
    const styles = useStyles();
    const idPrefix = useId('card-title');
    const [selected1, setSelected1] = React.useState(false);
    const [selected2, setSelected2] = React.useState(false);
    const [selected3, setSelected3] = React.useState(false);
    const [selected4, setSelected4] = React.useState(false);
    const setCheckboxState = React.useCallback(({ selected, checked }: {
        selected?: boolean;
        checked?: boolean | 'mixed';
    }, setFn: React.Dispatch<React.SetStateAction<boolean>>) => setFn(!!(selected || checked)), []);
    const onSelected1Change = React.useCallback((_: React.MouseEvent | React.KeyboardEvent | React.ChangeEvent, state: {
        selected?: boolean;
        checked?: boolean | 'mixed';
    }) => setCheckboxState(state, setSelected1), [setCheckboxState]);
    const onSelected2Change = React.useCallback((_: React.MouseEvent | React.KeyboardEvent | React.ChangeEvent, state: {
        selected?: boolean;
        checked?: boolean | 'mixed';
    }) => setCheckboxState(state, setSelected2), [setCheckboxState]);
    const onSelected3Change = React.useCallback((_: React.MouseEvent | React.KeyboardEvent | React.ChangeEvent, state: {
        selected?: boolean;
        checked?: boolean | 'mixed';
    }) => setCheckboxState(state, setSelected3), [setCheckboxState]);
    const onSelected4Change = React.useCallback((_: React.MouseEvent | React.KeyboardEvent | React.ChangeEvent, state: {
        selected?: boolean;
        checked?: boolean | 'mixed';
    }) => setCheckboxState(state, setSelected4), [setCheckboxState]);
    return (<div className={styles.main}>
      <div className={styles.row}>
        <Card className={styles.card} floatingAction={<Checkbox aria-labelledby={`${idPrefix}-1`} onChange={onSelected1Change} checked={selected1}/>} selected={selected1} onSelectionChange={onSelected1Change}>
          <CardPreview className={styles.grayBackground} logo={<img className={styles.logoBadge} src={resolveAsset('logo3.svg')} alt="Figma app logo"/>}>
            <img className={styles.smallRadius} src={resolveAsset('office1.png')} alt="Presentation Preview"/>
          </CardPreview>

          <CardHeader header={<Text id={`${idPrefix}-1`} weight="semibold">
                iOS App Prototype
              </Text>} description={<Caption1 className={styles.caption}>You created 53m ago</Caption1>} action={<Button appearance="transparent" icon={<MoreHorizontal20Regular />} aria-label="More actions"/>}/>
        </Card>

        <Card className={styles.card} floatingAction={<Checkbox aria-labelledby={`${idPrefix}-2`} onChange={onSelected2Change} checked={selected2}/>} selected={selected2} onSelectionChange={onSelected2Change}>
          <CardPreview className={styles.grayBackground} logo={<img className={styles.logoBadge} src={resolveAsset('logo3.svg')} alt="Figma app logo"/>}>
            <img className={styles.smallRadius} src={resolveAsset('office1.png')} alt="Presentation Preview"/>
          </CardPreview>

          <CardHeader header={<Text id={`${idPrefix}-2`} weight="semibold">
                iOS App Prototype
              </Text>} description={<Caption1 className={styles.caption}>You created 53m ago</Caption1>} action={<Button appearance="transparent" icon={<MoreHorizontal20Regular />} aria-label="More actions"/>}/>
        </Card>
      </div>

      <div className={styles.row}>
        <Card className={styles.card} selected={selected3} onSelectionChange={onSelected3Change} floatingAction={<Checkbox aria-labelledby={`${idPrefix}-3`} onChange={onSelected3Change} checked={selected3}/>}>
          <CardHeader image={<img src={resolveAsset('docx.png')} alt="Microsoft Word Logo"/>} header={<Text id={`${idPrefix}-3`} weight="semibold">
                Secret Project Briefing
              </Text>} description={<Caption1 className={styles.caption}>OneDrive &gt; Documents</Caption1>}/>
        </Card>

        <Card className={styles.card} selected={selected4} onSelectionChange={onSelected4Change} floatingAction={<Checkbox aria-labelledby={`${idPrefix}-4`} onChange={onSelected4Change} checked={selected4}/>}>
          <CardHeader image={<img src={resolveAsset('xlsx.png')} alt="Microsoft Excel Logo"/>} header={<Text id={`${idPrefix}-4`} weight="semibold">
                Team Budget
              </Text>} description={<Caption1 className={styles.caption}>OneDrive &gt; Spreadsheets</Caption1>}/>
        </Card>
      </div>
    </div>);
};

export default SelectableIndicator;

Selectable Indicator Radio

Loading interactive example. Full source is available below.

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

import { useId } from "@coreai-ds/react-components";
import * as React from 'react';
import { RadioGroup } from "@coreai-ds/react-components";
import { Text } from "@coreai-ds/react-components";
import { Card } from "@coreai-ds/react-components";
import { Radio } from "@coreai-ds/react-components";
import { CardHeader } from "@coreai-ds/react-components";

export const SelectableIndicatorRadio = () => {
    const options = [
        { value: 'option-1', label: 'Option 1', description: 'The recommended default' },
        { value: 'option-2', label: 'Option 2', description: 'A balanced choice' },
        { value: 'option-3', label: 'Option 3', description: 'For advanced needs' },
        { value: 'option-4', label: 'Option 4', description: 'Maximum flexibility' },
    ];
    const idPrefix = useId('card-title');
    const groupLabelId = useId('card-radio-group-label');
    const [selectedValue, setSelectedValue] = React.useState<string>('');
    const onChange = React.useCallback((_: React.FormEvent<HTMLDivElement>, data: {
        value: string;
    }) => setSelectedValue(data.value), []);
    const onSelectionChange = React.useCallback((value: string) => () => setSelectedValue(value), []);
    const styles = /* css */ `
      .card-selectable-radio-example {
        display: flex;
        flex-direction: column;
        gap: var(--spacingVerticalL);
      }

      .card-selectable-radio-example__row {
        display: flex;
        flex-wrap: wrap;
        gap: var(--spacingHorizontalL);
      }

      .card-selectable-radio-example__card {
        height: fit-content;
        max-width: 400px;
        width: 100%;
      }

      .card-selectable-radio-example__caption {
        color: var(--colorNeutralForeground3);
      }
    `;
    return (<>
        <style>{styles}</style>
        <RadioGroup aria-labelledby={groupLabelId} value={selectedValue} onChange={onChange}>
          <div className="card-selectable-radio-example">
            <Text id={groupLabelId} weight="semibold">
              Select an option
            </Text>
            <div className="card-selectable-radio-example__row">
              {options.map(({ value, label, description }) => {
            const titleId = `${idPrefix}-${value}`;
            return (<Card key={value} className="card-selectable-radio-example__card" floatingActionPosition="left" floatingAction={<Radio value={value} aria-labelledby={titleId}/>} selected={selectedValue === value} onSelectionChange={onSelectionChange(value)}>
                    <CardHeader header={<Text id={titleId} weight="semibold">
                          {label}
                        </Text>} description={<Text preset="bodyS" className="card-selectable-radio-example__caption">
                          {description}
                        </Text>}/>
                  </Card>);
        })}
            </div>
          </div>
        </RadioGroup>
      </>);
};

export default SelectableIndicatorRadio;

Size

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 { Subtitle1 } from "@coreai-ds/react-components";
import type { CardProps } from "@coreai-ds/react-components";
import { Card } from "@coreai-ds/react-components";
import { CardHeader } from "@coreai-ds/react-components";
import { Text } from "@coreai-ds/react-components";
import { Caption1 } from "@coreai-ds/react-components";
import { mergeClasses } from "@coreai-ds/react-components";

const useStyles = makeStyles({
    main: {
        display: 'flex',
        flexDirection: 'column',
        flexWrap: 'wrap',
        columnGap: '16px',
        rowGap: '36px',
    },
    title: { margin: '0 0 12px' },
    card: {
        maxWidth: '300px',
        width: '100%',
        height: 'fit-content',
    },
    flex: {
        gap: '4px',
        display: 'flex',
        flexDirection: 'row',
        alignItems: 'center',
    },
    appIcon: {
        borderRadius: '4px',
        height: '32px',
    },
    caption: {
        color: tokens.colorNeutralForeground3,
    },
    cardFooter: {
        alignItems: 'center',
        justifyContent: 'space-between',
    },
});

const Title = ({ children }: React.PropsWithChildren<{}>) => {
    const styles = useStyles();
    return (<Subtitle1 as="h4" block className={styles.title}>
      {children}
    </Subtitle1>);
};

const resolveAsset = (asset: string) => {
    const ASSET_URL = 'https://raw.githubusercontent.com/microsoft/fluentui/master/packages/react-components/react-card/stories/src/assets/';
    return `${ASSET_URL}${asset}`;
};

const CardExample = (props: CardProps) => {
    const styles = useStyles();
    return (<Card className={styles.card} {...props}>
      <header className={styles.flex}>
        <img className={styles.appIcon} src={resolveAsset('logo.svg')} alt="Application one logo"/>
        <img className={styles.appIcon} src={resolveAsset('logo2.svg')} alt="Application two logo"/>
      </header>

      <CardHeader header={<Text as="h5" weight="semibold" style={{ margin: 0 }}>
            Alert in Teams when a new document is uploaded in channel
          </Text>} description={<Caption1 className={styles.caption}>By Microsoft</Caption1>}/>

      <footer className={mergeClasses(styles.flex, styles.cardFooter)}>
        <span>Automated</span>
        <span>3290</span>
      </footer>
    </Card>);
};

export const Size = (): JSXElement => {
    const styles = useStyles();
    return (<div className={styles.main}>
      <section>
        <Title>'small'</Title>
        <CardExample size="small"/>
      </section>

      <section>
        <Title>'medium' (Default)</Title>
        <CardExample size="medium"/>
      </section>

      <section>
        <Title>'large'</Title>
        <CardExample size="large"/>
      </section>
    </div>);
};

export default Size;

Templates

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 { Card } from "@coreai-ds/react-components";
import { mergeClasses } from "@coreai-ds/react-components";
import { Badge } from "@coreai-ds/react-components";
import { Checkbox } from "@coreai-ds/react-components";
import { Text } from "@coreai-ds/react-components";
import { Caption1 } from "@coreai-ds/react-components";
import { AlertUrgent16Filled } from "@fluentui/react-icons";
import { CircleHalfFill16Regular } from "@fluentui/react-icons";
import { Attach16Regular } from "@fluentui/react-icons";
import { Body1 } from "@coreai-ds/react-components";
import { CheckmarkCircle16Regular } from "@fluentui/react-icons";
import { Comment16Regular } from "@fluentui/react-icons";
import { CardPreview } from "@coreai-ds/react-components";
import { CardHeader } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { MoreHorizontal20Regular } from "@fluentui/react-icons";
import * as React from 'react';
const useStyles = makeStyles({
    container: {
        gap: '16px',
        display: 'flex',
        flexWrap: 'wrap',
    },
    card: {
        maxWidth: '280px',
        width: '100%',
        height: 'fit-content',
    },
    flex: {
        gap: '4px',
        display: 'flex',
        flexDirection: 'row',
        alignItems: 'center',
    },
    labels: { gap: '6px' },
    footer: { gap: '12px' },
    caption: {
        color: tokens.colorNeutralForeground3,
    },
    taskCheckbox: {
        display: 'flex',
        alignItems: 'flex-start',
    },
    grid: {
        gap: '16px',
        display: 'flex',
        flexDirection: 'column',
        width: '100%',
    },
});
const resolveAsset = (asset: string) => {
    const ASSET_URL = 'https://raw.githubusercontent.com/microsoft/fluentui/master/packages/react-components/react-card/stories/src/assets/';
    return `${ASSET_URL}${asset}`;
};
const powerpointLogoURL = resolveAsset('pptx.png');
const excelLogo = resolveAsset('xlsx.png');
const wordLogo = resolveAsset('docx.png');
export const Templates = (): JSXElement => {
    const styles = useStyles();
    return (<div className={styles.container}>
      <Card className={styles.card}>
        <header className={mergeClasses(styles.flex, styles.labels)}>
          <Badge color="severe" shape="rounded" appearance="tint">
            Red
          </Badge>

          <Badge color="success" shape="rounded" appearance="tint">
            Green
          </Badge>

          <Badge color="brand" shape="rounded" appearance="tint">
            Blue
          </Badge>
        </header>

        <div className={styles.taskCheckbox}>
          <Checkbox id="components-card-card--templates-task-1"/>

          <label htmlFor="components-card-card--templates-task-1">
            <Text block weight="semibold">
              Task title
            </Text>

            <Caption1 block className={styles.caption}>
              Donut chocolate bar oat cake. Dragée tiramisu lollipop bear claw. Marshmallow pastry jujubes toffee sugar
              plum.
            </Caption1>
          </label>
        </div>

        <div className={styles.taskCheckbox}>
          <Checkbox id="components-card-card--templates-task-2"/>

          <label htmlFor="components-card-card--templates-task-2">
            <Text block weight="semibold">
              Task title
            </Text>

            <Caption1 block className={styles.caption}>
              Donut chocolate bar oat cake. Dragée tiramisu lollipop bear claw. Marshmallow pastry jujubes toffee sugar
              plum.
            </Caption1>
          </label>
        </div>

        <footer className={mergeClasses(styles.flex, styles.footer)}>
          <AlertUrgent16Filled primaryFill="#C4314B"/>
          <CircleHalfFill16Regular primaryFill="#0078DB"/>

          <div className={styles.flex}>
            <Attach16Regular />
            <Body1>4</Body1>
          </div>

          <div className={styles.flex}>
            <CheckmarkCircle16Regular />
            <Body1>2/12</Body1>
          </div>

          <Comment16Regular />
        </footer>
      </Card>

      <Card className={styles.card}>
        <CardPreview>
          <img src={resolveAsset('intelligence.png')} alt="Intelligence - Design to Amplify"/>
        </CardPreview>
      </Card>

      <div className={styles.grid} role="list">
        <Card className={styles.card} size="small" role="listitem">
          <CardHeader image={{ as: 'img', src: powerpointLogoURL, alt: 'PowerPoint app logo' }} header={<Text weight="semibold">Team Offsite 2020</Text>} description={<Caption1 className={styles.caption}>OneDrive &gt; Presentations</Caption1>} action={<Button appearance="transparent" aria-label="More actions" icon={<MoreHorizontal20Regular />}/>}/>
        </Card>

        <Card className={styles.card} size="small" role="listitem">
          <CardHeader image={{ as: 'img', src: excelLogo, alt: 'Excel app logo' }} header={<Text weight="semibold">Team Budget</Text>} description={<Caption1 className={styles.caption}>OneDrive &gt; Spreadsheets</Caption1>} action={<Button appearance="transparent" aria-label="More actions" icon={<MoreHorizontal20Regular />}/>}/>
        </Card>

        <Card className={styles.card} size="small" role="listitem">
          <CardHeader image={{ as: 'img', src: wordLogo, alt: 'Word app logo' }} header={<Text weight="semibold">Secret Project Briefing</Text>} description={<Caption1 className={styles.caption}>OneDrive &gt; Documents</Caption1>} action={<Button appearance="transparent" aria-label="More actions" icon={<MoreHorizontal20Regular />}/>}/>
        </Card>
      </div>
    </div>);
};

export default Templates;

With Action

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 { Subtitle1 } from "@coreai-ds/react-components";
import { Body1 } from "@coreai-ds/react-components";
import { Card } from "@coreai-ds/react-components";
import { CardPreview } from "@coreai-ds/react-components";
import { CardHeader } from "@coreai-ds/react-components";
import { Caption1 } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { MoreHorizontal20Regular } from "@fluentui/react-icons";
import { CardFooter } from "@coreai-ds/react-components";
import { Open16Regular } from "@fluentui/react-icons";
import { Text } from "@coreai-ds/react-components";
import { Link } from "@coreai-ds/react-components";

const useStyles = makeStyles({
    main: {
        display: 'flex',
        flexWrap: 'wrap',
        flexDirection: 'column',
        columnGap: '16px',
        rowGap: '36px',
    },
    title: { margin: '0 0 12px' },
    description: { margin: '0 0 12px' },
    card: {
        maxWidth: '400px',
        width: '100%',
        height: 'fit-content',
    },
    link: {
        color: tokens.colorNeutralForeground1,
        ':hover': {
            color: tokens.colorNeutralForeground1,
            textDecoration: 'none',
        },
    },
    text: { margin: '0' },
});

const Header = ({ title, description }: Record<string, string>) => {
    const styles = useStyles();
    return (<>
      {title ? (<Subtitle1 as="h4" block className={styles.title}>
          {title}
        </Subtitle1>) : null}

      {description ? (<Body1 as="p" block className={styles.description}>
          {description}
        </Body1>) : null}
    </>);
};

const resolveAsset = (asset: string) => {
    const ASSET_URL = 'https://raw.githubusercontent.com/microsoft/fluentui/master/packages/react-components/react-card/stories/src/assets/';
    return `${ASSET_URL}${asset}`;
};

export const WithAction = (): JSXElement => {
    const styles = useStyles();
    const linkRef = React.useRef<HTMLAnchorElement>(null);
    const onActionCardKeyDown = (ev: React.KeyboardEvent<HTMLDivElement>) => {
        if (ev.key === 'Enter') {
            onActionCardClick();
        }
    };
    const onActionCardClick = () => {
        alert('Opened Classroom Collaboration app');
    };
    const onLinkedCardClick = () => {
        linkRef.current?.click();
    };
    const onLinkedCardKeyDown = (ev: React.KeyboardEvent<HTMLDivElement>) => {
        if (ev.key === 'Enter') {
            onLinkedCardClick();
        }
    };
    return (<div className={styles.main}>
      <section>
        <Header title="Card with click event" description="This card has both a root click event and an Open button that performs the same action. Adding enter key handling to the card root is optional since the Open button also provides keyboard access."/>
        <Card className={styles.card} onClick={onActionCardClick} onKeyDown={onActionCardKeyDown} focusMode="off">
          <CardPreview>
            <img src={resolveAsset('office2.png')} alt="Sales Presentation Preview"/>
          </CardPreview>

          <CardHeader image={<img src={resolveAsset('pptx.png')} width="32px" height="32px" alt="Microsoft PowerPoint logo"/>} header={<Body1 as="h5" style={{ margin: 0, fontWeight: 'bold' }}>
                App Name
              </Body1>} description={<Caption1>Developer</Caption1>} action={<Button appearance="transparent" icon={<MoreHorizontal20Regular />} aria-label="More options"/>}/>

          <p className={styles.text}>
            Donut chocolate bar oat cake. Dragée tiramisu lollipop bear claw. Marshmallow pastry jujubes toffee sugar
            plum.
          </p>

          <CardFooter>
            <Button appearance="primary" icon={<Open16Regular />} onClick={onActionCardClick}>
              Open
            </Button>
          </CardFooter>
        </Card>
      </section>

      <section>
        <Header title="Linked Card" description="When a card doesn't have a separate button within its contents, it usually makes the most sense for the title text of the card to become the additional interactive element (a link in this example)."/>
        <Card className={styles.card} onClick={onLinkedCardClick} onKeyDown={onLinkedCardKeyDown} focusMode="off">
          <CardPreview>
            <img src={resolveAsset('office2.png')} alt="Sales Presentation Preview"/>
          </CardPreview>

          <CardHeader image={<img src={resolveAsset('pptx.png')} width="32px" height="32px" alt="Microsoft PowerPoint logo"/>} header={<Text as="h5" style={{ margin: 0 }}>
                <Link href="https://www.microsoft.com/" target="_blank" ref={linkRef} className={styles.link}>
                  <b>App Name</b>
                </Link>
              </Text>} description={<Caption1>Developer</Caption1>} action={<Button appearance="transparent" icon={<MoreHorizontal20Regular />} aria-label="More options"/>}/>
        </Card>
      </section>
    </div>);
};

export default WithAction;