feat: allow custom spinners for `ion-spinner`/`ion-loading`
Prequisites
- [X] I have read the Contributing Guidelines.
- [X] I agree to follow the Code of Conduct.
- [X] I have searched for existing issues that already include this feature request, without success.
Describe the Feature Request
Allow an HTML element (such as one created with createElement()) to be given to the ion-spinner. This functionality should be able to come through to ion-loading, as it uses an ion-spinner under the hood.
Describe the Use Case
Sometimes I want a spinner that "just works", but want it to be slightly more "on brand" than a stock style.
I created a Vue component that holds an animated SVG (for easy reuse), but have no way to use it with Ionic.
Note: a Vue component gets compiled to standard HTML elements, so the root element of the Vue component can be passed to the ion-spinner.
Maybe using a custom spinner design violates someone's interface design guidelines/rules? (looking at you Apple)
Describe Preferred Solution
Allow an element to be given when creating a spinner using the spinner controller.
Not sure which way would be best.
Maybe change the spinner property/param to allow HTMLElement as well or something?
For the element version of ion-spinner, it could use a named slot: slot="spinner"?
Describe Alternatives
- Use a custom spinner instead of
ion-spinner. This can actually work in many cases, but not when I want to useion-loading. - Set the spinner style to
noneand target the background of the spinner with CSS. e.g.background: url(#my-spinner-svg)Someone on the Ionic forum mentioned doing this as a workaround. I can find it again if needed. This unfortunately is more complex and only allows for a single SVG to be set.
Related Code
No response
Additional Information
As to implementing, I looked at Ionic's source, and I think this could get hairy. If it would be too complex, please say so and feel free to drop the request :).
I'll discuss this with the team; thanks for the issue!
@darrylnoakes You can use a custom spinner with ion-loading through clever use of css. I don't have time to document it now, but it is possible.
I'd also love to have this possibility, without a hacky CSS workaround.
I'm using tailwindcss with this css. Note that there are default values for each aspect of the spinner, but they can be overridden by the --loading-overlay-* variables:
@keyframes loading-spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.loading-overlay {
--backdrop-opacity: var(--loading-overlay-backdrop-opacity, 60%) !important;
& .loading-wrapper {
--background: var(
--loading-overlay-background,
theme('colors.neutral.900')
);
@apply rounded-xl py-5 pr-5 !important;
}
/* Customize the text of the loading message */
& .loading-content {
padding-left: var(--loading-overlay-size, 16px) !important;
font-size: var(
--loading-overlay-font-size,
theme('fontSize.lg')
) !important;
font-weight: var(
--loading-overlay-font-weight,
theme('fontWeight.normal')
) !important;
line-height: var(--loading-overlay-size, 20px);
color: var(--loading-overlay-text-color, white) !important;
@apply ml-0 !important;
/* Insert our custom spinner */
&::before {
content: '';
position: absolute;
left: var(--loading-overlay-left-margin, 18px);
width: var(--loading-overlay-size, 22px);
height: var(--loading-overlay-size, 22px);
border: 3px solid rgb(255 255 255 / 15%);
border-top: 3px solid rgb(255 255 255 / 80%);
border-radius: 50%;
animation: var(
--loading-overlay-animation,
loading-spin 1.5s linear infinite
);
}
}
}
.md .loading-overlay .loading-content {
/* On Android, move the spinner closer to the text */
@apply ml-2 !important;
&::before {
left: var(--loading-overlay-left-margin, 16px);
}
}
Then create a spinner like this:
const controller = await loadingController.create({
message: toValue(message),
spinner: null,
cssClass: 'loading-overlay',
})
Please add this option as soon as possible!