Skip to main content

Page Footer

Use the page footer when forms need to be saved, or inside a wizard. It’s a mandatory component inside the wizard template, which allows the user to perform the primary and secondary action of the wizard flow.

Example

Live Editor
function MyPageFooter() {
  const actions = {
    primaryAction: {
      onClick: () => console.log('primaryAction clicked'),
      label: 'Save',
      isLoading: true,
      disabled: true,
      tooltip: {
        content: 'Saving please wait...'
      },
      dataTestId: 'primary-btn'
    },
    secondaryAction: {
      onClick: () => console.log('secondaryAction clicked'),
      label: 'Reset',
      dataTestId: 'secondary-btn'
    },
    destructiveAction: {
      onClick: () => console.log('destructiveAction clicked'),
      label: 'Delete',
      dataTestId: 'destructive-btn',
      disabled: true,
      tooltip: {
        content: 'Delete action is disabled'
      }
    }
  };
  return (
    <PageFooter
      primaryAction={actions.primaryAction}
      secondaryAction={actions.secondaryAction}
      destructiveAction={actions.destructiveAction}
      contextMessage="This is a contextual message."
      isFluidWidth
      css={{ position: 'relative' }} // to fit with Preview Container.
    />
  );
}
Result
Loading...

Variants

Action with Icons

Primary action and destructive action can add an icon with iconName and iconAlignment.

Live Editor
function MyPageFooter() {
  const actions = {
    primaryAction: {
      label: 'Next',
      dataTestId: 'primary-btn',
      iconName: 'ChevronRight',
      iconAlignment: 'right'
    },
    secondaryAction: {
      label: 'Secondary',
      dataTestId: 'secondary-btn'
    },
    destructiveAction: {
      label: 'Delete',
      dataTestId: 'destructive-btn',
      iconName: 'Trash',
      iconAlignment: 'left'
    }
  };
  return (
    <>
      <PageFooter
        primaryAction={actions.primaryAction}
        secondaryAction={actions.secondaryAction}
        destructiveAction={actions.destructiveAction}
        isFluidWidth
        css={{ position: 'relative' }} // to fit with Preview Container.
      />
    </>
  );
}
Result
Loading...

Actions with Type Property

Primary Action also can specify the type as button, submit, or reset.

Live Editor
function MyPageFooter() {
  const actions = {
    primaryAction: {
      label: 'Next',
      dataTestId: 'primary-btn',
      type: 'submit'
    },
    secondaryAction: {
      label: 'Secondary',
      dataTestId: 'secondary-btn'
    },
    destructiveAction: {
      label: 'Delete',
      dataTestId: 'destructive-btn',
    }
  };
  return (
    <>
      <PageFooter
        primaryAction={actions.primaryAction}
        secondaryAction={actions.secondaryAction}
        destructiveAction={actions.destructiveAction}
        isFluidWidth
        css={{ position: 'relative' }} // to fit with Preview Container.
      />
    </>
  );
}
Result
Loading...

Checkbox

note

When the checkbox is used destructiveAction and contextMessage will be ignored and not displayed.

A checkbox can be added with same props as in Checkbox using prop checkboxProps;

Live Editor
function MyPageFooter() {
  const actions = {
    primaryAction: {
      label: 'Next',
      dataTestId: 'primary-btn'
    },
    secondaryAction: {
      label: 'Back',
      dataTestId: 'secondary-btn'
    }
  };

  const [termsCheck, setTermsCheck] = useState(false);
  const handleCheck = (e) => {
    setTermsCheck(e.target.checked);
  };

  const checkboxProps = {
    label: 'I’ve read and accept the Terms of Use for the Twitter Ad Network',
    helperText:
      'It is required to agree to the terms before enabling this feature.',
    checked: termsCheck,
    onChange: (e) => handleCheck(e),
    required: true
  };

  return (
    <PageFooter
      primaryAction={actions.primaryAction}
      secondaryAction={actions.secondaryAction}
      checkboxProps={checkboxProps}
      isFluidWidth
      css={{ position: 'relative' }} // to fit with Preview Container.
    />
  );
}
Result
Loading...

Context Message

A short message contextMessage can be displayed in the footer for additional information on the status (eg. a feedback label if data has been saved), or to provide helpful information about the current, or upcoming step. If there is a destructive button inside the footer, as well as a context message, the messages moves to the right.

If the message is too long, it will be truncated. Using showTooltip to see the full measgage.

Live Editor
function MyPageFooter() {
  const actions = {
    primaryAction: {
      label: 'Next',
      dataTestId: 'primary-btn'
    },
    secondaryAction: {
      label: 'Back',
      dataTestId: 'secondary-btn'
    },
    destructiveAction: {
      label: 'Delete',
      dataTestId: 'destructive-btn'
    }
  };
  return (
    <>
      <PageFooter
        primaryAction={actions.primaryAction}
        contextMessage="This is a contextual message."
        isFluidWidth
        css={{ position: 'relative' }} // to fit with Preview Container.
      />
      <br />
      <PageFooter
        destructiveAction={actions.destructiveAction}
        primaryAction={actions.primaryAction}
        contextMessage="This is a contextual message."
        isFluidWidth
        css={{ position: 'relative' }} // to fit with Preview Container.
      />
      <br />
      <PageFooter
        primaryAction={actions.primaryAction}
        secondaryAction={actions.secondaryAction}
        contextMessage="This is a contextual message. This is a contextual message. This is a contextual message. This is a contextual message."
        isFluidWidth
        showTooltip
        css={{ position: 'relative' }} // to fit with Preview Container.
      />
    </>
  );
}
Result
Loading...

You can use the following props if you need to manage your action buttons with custom components.

customActionsLeft: This prop allows you to provide a custom component for the left-footer action area.

customActionsRight: This prop allows you to provide a custom component for the right-footer action area.

When considering the integration of custom slots within the PageFooter component, we encourage developers to adhere to the following guidelines:

  1. Responsiveness is Key: Ensure that all custom content inserted into the PageFooter component remains fully responsive across various screen sizes and resolutions. This ensures a consistent user experience and maintains the integrity of your application's design.
  2. Stay True to Atlas Design Guidelines: The PageFooter component is an essential part of the Atlas design system. Custom content should seamlessly blend with Atlas design principles to maintain visual harmony and a cohesive user interface.
  3. Prefer Atlas Components: Whenever possible, we recommend using Atlas components as custom content within the PageFooter. This ensures compatibility, consistency, and adherence to the Atlas design language.

By following these guidelines, you can effectively leverage custom slots in the PageFooter component while maintaining the quality, responsiveness, and visual coherence of your application.

Live Editor
function MyPageFooter() {
  const [termsChecked, setTermsChecked] = useState(false);
  const handleChange = (e) => {
    setTermsChecked(e.target.checked);
  };
  const CustomActionsLeft = () => {
    return <Button label="Delete" kind="negative" />;
  };

  const CustomActionsLeftWithCheckbox = () => {
    return (
      <Checkbox
        label="I agree to the Terms and Conditions"
        helperText="It’s required to agree to the terms before enabling this feature."
        checked={termsChecked}
        onChange={(e) => handleChange(e)}
        required
      />
    );
  };

  const CustomActionsRight = () => {
    return (
      <>
        <Button label="Save" kind="primary" />
      </>
    );
  };

  return (
    <>
      <PageFooter
        contextMessage="This is a contextual message."
        customActionsLeft={<CustomActionsLeft />}
        customActionsRight={<CustomActionsRight />}
        isFluidWidth
        css={{ position: 'relative' }} // to fit with Preview Container.
      />
      <PageFooter
        customActionsLeft={<CustomActionsLeftWithCheckbox />}
        customActionsRight={<CustomActionsRight />}
        isFluidWidth
        css={{ position: 'relative' }} // to fit with Preview Container.
      />
    </>
  );
}
Result
Loading...

Disabled Actions

Actions can be disabled under certain conditions with disabled.

Live Editor
function MyPageFooter() {
  const actions = {
    primaryAction: {
      label: 'Primary',
      dataTestId: 'primary-btn',
      disabled: true
    },
    secondaryAction: {
      label: 'Secondary',
      dataTestId: 'secondary-btn',
      disabled: true
    },
    destructiveAction: {
      label: 'Destructive',
      dataTestId: 'destructive-btn',
      disabled: true
    }
  };
  return (
    <>
      <PageFooter
        primaryAction={actions.primaryAction}
        secondaryAction={actions.secondaryAction}
        destructiveAction={actions.destructiveAction}
        isFluidWidth
        css={{ position: 'relative' }} // to fit with Preview Container.
      />
    </>
  );
}
Result
Loading...

Layouts

The wizard footer is available as a fixed content width version (default), you can manage fixed width using layout prop, as well as a fluid version with isFluidWidth.

Live Editor
function MyPageFooter() {
  const [show, setShow] = useState(false);
  const [showXL, setShowXL] = useState(false);
  const [showFluid, setShowFluid] = useState(false);

  const actions = {
    primaryAction: {
      label: 'Primary',
      dataTestId: 'primary-btn'
    },
    secondaryAction: {
      label: 'Secondary',
      dataTestId: 'secondary-btn',
      disabled: true
    },
    destructiveAction: {
      label: 'Destructive',
      dataTestId: 'destructive-btn'
    }
  };
  return (
    <>
      <Button
        label="Default layout!"
        onClick={() => {
          setShow(!show);
          setShowFluid(false);
          setShowXL(false);
        }}
      />
      {show && (
        <PageFooter
          primaryAction={actions.primaryAction}
          secondaryAction={actions.secondaryAction}
          destructiveAction={actions.destructiveAction}
          contextMessage="This is a contextual message."
          css={{ margin: 0 }} // due to margin of Preview
        />
      )}

      <Button
        label="XLlayout!"
        onClick={() => {
          setShowXL(!showXL);
          setShowFluid(false);
          setShow(false);
        }}
      />
      {showXL && (
        <PageFooter
          primaryAction={actions.primaryAction}
          secondaryAction={actions.secondaryAction}
          destructiveAction={actions.destructiveAction}
          contextMessage="This is a contextual message."
          css={{ margin: 0 }} // due to margin of Preview
          layout="x-large"
        />
      )}

      <Button
        label="Fluid layout!"
        onClick={() => {
          setShowFluid(!showFluid);
          setShow(false);
          setShowXL(false);
        }}
      />
      {showFluid && (
        <PageFooter
          primaryAction={actions.primaryAction}
          secondaryAction={actions.secondaryAction}
          destructiveAction={actions.destructiveAction}
          contextMessage="This is a contextual message."
          isFluidWidth
          css={{ margin: 0 }} // due to margin of Preview
        />
      )}
    </>
  );
}
Result
Loading...

Props

NameTypeDefault
secondaryAction
Secondary action
Omit<Action, "type" | "iconName" | "iconAlignment">
destructiveAction
Destructive action
Omit<Action, "type">
contextMessage
Context Message
string
showTooltip
Show the Tooltip for Context Message
boolean
false
isFluidWidth
Fluid Layout
boolean
false
checkboxProps
Checkbox properties
CheckboxProps
dataTestId
Context Message
string
"page-footer"
layout
Layout to set Max-width
"large" | "x-large"
"large"
customActionsLeft
Custom Action for the left side of the footer
ReactNode
css
Add custom styles to this component. Use with caution. Learn more here: Link
SupportedStyleAttributes
inputFieldCss
SupportedStyleAttributes
primaryAction
Primary action and it's mandatory
Action
customActionsRight
Custom Action for the right side of the footer
ReactNode
data-{foo}
Data attributes can be used by testing libraries to retrieve components or assert their existence
string
* - the prop is required.