Skip to main content
MultiContentModule
@coinbase/cds-web@8.13.6
A versatile container designed to streamline user experiences across Critical User Journeys. Accommodates a range of content including an illustration, input fields (text inputs, list cells, etc.), and an action button.
Import
import { MultiContentModule } from '@coinbase/cds-web/multi-content-module/MultiContentModule'
SourceView source codeStorybookView StorybookFigmaView Figma
Related components

Session expired

Session Expired is a form of an Identity module that inform users when their login session has timed out. These modules require users to take action by either logging in again or switching to another account before they can continue using the product.

Loading...
Live Code
function Example() {
  const onClickConsole = () => console.log('onClick');
  const action = (
    <VStack paddingTop={2}>
      <ButtonGroup accessibilityLabel="Group" direction="vertical">
        <Button accessibilityLabel="Continue" onClick={onClickConsole}>
          Continue
        </Button>
        <Button accessibilityLabel="Cancel" onClick={onClickConsole} variant="secondary">
          Cancel
        </Button>
      </ButtonGroup>
    </VStack>
  );
  return (
    <HStack justifyContent="center">
      <MultiContentModule
        bordered
        action={action}
        title="Session Expired"
        description="Your session expired. Don't worry simply sign in again."
        accessibilityLabel="Session expired section"
        pictogram="waiting"
      >
        <Box bordered borderColor="bgLinePrimary" borderRadius={300}>
          <ListCell
            description="Satoshi Nakamoto"
            media={<Avatar alt="Sneezy" colorScheme="blue" name="Sneezy" />}
            title="satoshi@coinbase.com"
          />
        </Box>
      </MultiContentModule>
    </HStack>
  );
}

Account Recovery

Account Recovery is used to explain to users the options they have when they are having difficultly accessing their account.

Loading...
Live Code
function Example() {
  const listItems = [
    {
      title: 'Upload your ID to login',
      description:
        'Once your identity is verified, you can update your phone number and regain full access to your account.',
    },
    {
      title: 'Troubleshoot',
      description: 'Visit our Help Center to find quick solutions and troubleshoot',
    },
  ];
  const onClickConsole = () => console.log('onClick');
  return (
    <HStack justifyContent="center">
      <MultiContentModule
        bordered
        title="Try another way"
        description="Select how you would like to verify it's you who owns this account"
        accessibilityLabel="Account recovery section"
        maxWidth={563}
        action={
          <Button accessibilityLabel="Back" onClick={onClickConsole} variant="secondary">
            Go back
          </Button>
        }
      >
        {listItems.map(({ title, description }, index) => (
          <ListCell
            outerSpacing={{
              padding: 0,
            }}
            key={index}
            multiline
            description={description}
            title={title}
            accessory="arrow"
          />
        ))}
      </MultiContentModule>
    </HStack>
  );
}

Login

Login page is the entry point for users to access Coinbase products. Login features third-party sign in options to accelerate the sign in process.

Loading...
Live Code
function Example() {
  const theme = useTheme();
  const spectrum = theme.activeColorScheme;
  const fill = spectrum === 'light' ? 'black' : 'white';
  const size = 24;
  const onClickConsole = () => console.log('onClick');
  const PasskeyIcon = () => {
    return (
      <svg
        fill="none"
        height={size}
        viewBox="0 0 16 17"
        width={size}
        xmlns="http://www.w3.org/2000/svg"
      >
        <path
          d="M5.373.219C4.025.506 2.899 1.637 2.556 3.04c-.119.487-.119 1.298 0 1.784.347 1.423 1.465 2.53 2.848 2.822.225.048.447.06.897.048.506-.02.64-.036.928-.133.798-.264 1.391-.686 1.857-1.326.297-.402.478-.77.62-1.237.1-.328.107-.41.107-1.066 0-.657-.008-.738-.106-1.066C9.33 1.617 8.458.713 7.229.304 6.93.202 6.826.19 6.261.178c-.422-.008-.715.004-.888.04zM12.563 4.84a2.81 2.81 0 00-1.481.856c-.783.823-1.02 2.075-.593 3.15.217.551.707 1.127 1.197 1.41l.241.142.004 2.27v2.271l.605.616.604.62 1.023-1.054 1.027-1.054-.612-.628-.612-.628.604-.62c.328-.341.6-.637.6-.657 0-.02-.216-.264-.481-.536-.265-.271-.474-.502-.466-.51.011-.008.162-.094.335-.195a2.972 2.972 0 001.363-1.804c.095-.381.107-1.09.02-1.456A2.952 2.952 0 0013.9 4.881c-.305-.085-1.024-.106-1.336-.04zm1.04 1.346c.193.138.383.483.383.702 0 .206-.166.543-.328.668-.182.142-.51.211-.72.155a.89.89 0 01-.612-.811c-.004-.673.743-1.09 1.276-.714zM4.168 9.065C2.343 9.352.81 10.69.233 12.499c-.197.624-.233.94-.233 2.14v1.09h10.667v-4.621l-.316-.308a4.4 4.4 0 01-.838-1.111l-.134-.264-.435-.15C8.237 9.032 7.901 9 6.1 9.004c-1.126.004-1.68.02-1.932.06z"
          fill={fill}
        />
      </svg>
    );
  };
  const GoogleIcon = () => {
    return (
      <svg
        fill="none"
        height={size}
        viewBox="0 0 25 25"
        width={size}
        xmlns="http://www.w3.org/2000/svg"
      >
        <g id="icon">
          <g id="logo googleg 48dp">
            <path
              clipRule="evenodd"
              d="M24.02 12.7729C24.02 11.922 23.9436 11.1038 23.8018 10.3184H12.5V14.9602H18.9582C18.68 16.4602 17.8345 17.7311 16.5636 18.582V21.5929H20.4418C22.7109 19.5038 24.02 16.4274 24.02 12.7729Z"
              fill={fill}
              fillRule="evenodd"
              id="Shape"
            />
            <path
              clipRule="evenodd"
              d="M12.5 24.4998C15.74 24.4998 18.4564 23.4252 20.4418 21.5925L16.5636 18.5816C15.4891 19.3016 14.1145 19.7271 12.5 19.7271C9.37455 19.7271 6.72909 17.6161 5.78546 14.7798H1.77637V17.8889C3.75091 21.8107 7.80909 24.4998 12.5 24.4998Z"
              fill={fill}
              fillRule="evenodd"
              id="Shape_2"
            />
            <path
              clipRule="evenodd"
              d="M5.78545 14.7801C5.54545 14.0601 5.40909 13.291 5.40909 12.5001C5.40909 11.7091 5.54545 10.9401 5.78545 10.2201V7.11096H1.77636C0.963636 8.73096 0.5 10.5637 0.5 12.5001C0.5 14.4364 0.963636 16.2691 1.77636 17.8891L5.78545 14.7801Z"
              fill={fill}
              fillRule="evenodd"
              id="Shape_3"
            />
            <path
              clipRule="evenodd"
              d="M12.5 5.27273C14.2618 5.27273 15.8436 5.87818 17.0873 7.06727L20.5291 3.62545C18.4509 1.68909 15.7345 0.5 12.5 0.5C7.80909 0.5 3.75091 3.18909 1.77637 7.11091L5.78546 10.22C6.72909 7.38364 9.37455 5.27273 12.5 5.27273Z"
              fill={fill}
              fillRule="evenodd"
              id="Shape_4"
            />
          </g>
        </g>
      </svg>
    );
  };
  const AppleIcon = () => {
    return (
      <svg
        fill="none"
        height={size}
        viewBox="0 0 24 24"
        width={size}
        xmlns="http://www.w3.org/2000/svg"
      >
        <g id="Apple Logo">
          <path
            d="M21.2808 18.424C20.933 19.2275 20.5213 19.9672 20.0442 20.6472C19.394 21.5743 18.8616 22.216 18.4513 22.5724C17.8153 23.1573 17.1338 23.4568 16.4041 23.4739C15.8802 23.4739 15.2485 23.3248 14.513 23.0224C13.7752 22.7214 13.0972 22.5724 12.4772 22.5724C11.827 22.5724 11.1296 22.7214 10.3837 23.0224C9.63662 23.3248 9.03481 23.4824 8.57468 23.498C7.87491 23.5278 7.1774 23.2197 6.48118 22.5724C6.03681 22.1848 5.48099 21.5204 4.81515 20.5791C4.10075 19.5739 3.51342 18.4084 3.05329 17.0795C2.56051 15.6442 2.31348 14.2543 2.31348 12.9087C2.31348 11.3673 2.64654 10.0379 3.31366 8.92385C3.83796 8.029 4.53546 7.32312 5.40844 6.80493C6.28142 6.28674 7.22468 6.02267 8.24048 6.00578C8.7963 6.00578 9.52518 6.1777 10.431 6.51559C11.3342 6.85462 11.9141 7.02655 12.1684 7.02655C12.3585 7.02655 13.0028 6.82552 14.0949 6.42473C15.1278 6.05305 15.9995 5.89916 16.7136 5.95978C18.6487 6.11595 20.1024 6.87876 21.0693 8.25303C19.3386 9.30163 18.4826 10.7703 18.4996 12.6544C18.5152 14.122 19.0476 15.3432 20.0939 16.3129C20.5681 16.7629 21.0977 17.1107 21.6868 17.3578C21.5591 17.7283 21.4242 18.0832 21.2808 18.424ZM16.8428 0.960131C16.8428 2.11039 16.4226 3.18439 15.5849 4.17847C14.5741 5.36023 13.3514 6.04311 12.0256 5.93536C12.0087 5.79736 11.9989 5.65213 11.9989 5.49951C11.9989 4.39526 12.4796 3.21349 13.3333 2.24724C13.7595 1.75801 14.3015 1.35122 14.9588 1.02671C15.6147 0.707053 16.2352 0.530273 16.8187 0.5C16.8357 0.653772 16.8428 0.807554 16.8428 0.960116V0.960131Z"
            fill={fill}
            id="path4"
          />
        </g>
      </svg>
    );
  };
  const socialMediaItems = [
    {
      name: 'Passkey',
      icon: <PasskeyIcon />,
    },
    {
      name: 'Google',
      icon: <GoogleIcon />,
    },
    {
      name: 'Apple',
      icon: <AppleIcon />,
    },
    {
      name: 'Wallet',
      icon: <Icon active color="foreground" name="wallet" size="m" />,
    },
  ];
  const end = (
    <VStack gap={1} paddingHorizontal={3}>
      <VStack>
        <HStack justifyContent="center" zIndex={1}>
          <Box background="background" paddingHorizontal={1.5}>
            <TextBody as="span" color="foregroundMuted">
              OR
            </TextBody>
          </Box>
        </HStack>
        <Divider marginTop={-1.5} paddingBottom={1.5} />
      </VStack>
      <HStack gap={2} justifyContent="space-between">
        {socialMediaItems.map(({ icon, name }) => (
          <VStack key={name} alignItems="center">
            <Pressable
              accessibilityLabel={name}
              background="secondary"
              borderColor="transparent"
              borderRadius="roundedFull"
              borderWidth="button"
              onClick={onClickConsole}
            >
              <Box padding={2}>{icon}</Box>
            </Pressable>
            <TextLabel2 as="span" color="foregroundMuted" paddingTop={1}>
              {name}
            </TextLabel2>
          </VStack>
        ))}
      </HStack>
    </VStack>
  );
  return (
    <HStack justifyContent="center">
      <MultiContentModule
        bordered
        action="Continue"
        actionAccessibilityLabel="Continue"
        title="Sign in to Coinbase"
        description={
          <TextBody as="p" color="foregroundMuted">
            By signing in, you agree to our{' '}
            <Link to="https://www.google.com/" openInNewWindow underline={false}>
              Privacy Policy
            </Link>
            . Not your device? Use a private window.
          </TextBody>
        }
        accessibilityLabel="Login section"
        pictogram={<LogoMark size={32} />}
        end={end}
      >
        <TextInput label="Email address" placeholder="Enter your email address" />
      </MultiContentModule>
    </HStack>
  );
}

Is this page useful?

Coinbase Design is an open-source, adaptable system of guidelines, components, and tools that aid the best practices of user interface design for crypto products.