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
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' }}
/>
);
}
Variants
Action with Icons
Primary action and destructive action can add an icon with iconName
and iconAlignment
.
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' }}
/>
</>
);
}
Actions with Type Property
Primary Action also can specify the type
as button
, submit
, or reset
.
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' }}
/>
</>
);
}
Checkbox
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
;
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' }}
/>
);
}
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.
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' }}
/>
<br />
<PageFooter
destructiveAction={actions.destructiveAction}
primaryAction={actions.primaryAction}
contextMessage="This is a contextual message."
isFluidWidth
css={{ position: 'relative' }}
/>
<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' }}
/>
</>
);
}
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:
- 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.
- 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.
- 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.
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' }}
/>
<PageFooter
customActionsLeft={<CustomActionsLeftWithCheckbox />}
customActionsRight={<CustomActionsRight />}
isFluidWidth
css={{ position: 'relative' }}
/>
</>
);
}
Disabled Actions
Actions can be disabled under certain conditions with disabled
.
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' }}
/>
</>
);
}
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
.
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 }}
/>
)}
<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 }}
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 }}
/>
)}
</>
);
}
Props
|
secondaryAction Secondary action | Omit<Action, "type" | "iconName" | "iconAlignment">
| — |
destructiveAction Destructive action | | — |
contextMessage Context Message | | — |
showTooltip Show the Tooltip for Context Message | | false |
isFluidWidth Fluid Layout | | false |
checkboxProps Checkbox properties | | — |
dataTestId Context Message | | "page-footer" |
layout Layout to set Max-width | | "large" |
customActionsLeft Custom Action for the left side of the footer | | — |
css Add custom styles to this component. Use with caution. Learn more here: Link | | — |
inputFieldCss | | — |
primaryAction Primary action and it's mandatory | | — |
customActionsRight Custom Action for the right side of the footer | | — |
data-{foo} Data attributes can be used by testing libraries to retrieve components or assert their existence | | — |
* - the prop is required. |