Skip to content
On this page

Button

This is a simple button.

Usage

This is a basic button, which defaults to a filled primary button. Try changing the props and slots to see how it reacts.

Props

ButtonSize buttonSizeAllows to change the color of the button Default value: ButtonSize.DEFAULT
ButtonColor colorAllows to change the mode the button is displayed Default value: ButtonColor.PRIMARY
ButtonMode modeMakes the HTML to be a "router-link" instead of a "button" Default value: ButtonMode.NORMAL
ComponentSkin skinIndicates which skin should be used for the component Default value: ComponentSkin.DESIGN_SYSTEM
pandads
string toIndicates the route to which the button should redirect when clicked
string hrefIndicates the URL to which the button should redirect when clicked

TIP

When the to prop is set, the button element will render as a <router-link> instead of a <button>. This prop has priority over the href prop if both are set.

When the href prop is set, the button element will render as a <a> instead of a <button>.

Options

Make it disabledDisable the button to not allow user interaction

Slots

defaultThe content of the button, usually a text
iconAn icon prepending the button content. It can be a svg, a component, an image or whatever
icon-onlyIf you want the button to only have an icon, you should use this slot instead of the "icon" one

WARNING

The icon-only slot should be used with no content in the default slot, as it may cause the button to look weird. This is not the case with the example as the icon-only example is detached with no possibility of using the default slot.

Implementation details

Ripple effect

The button has a ripple effect when clicked. This is done by creating a span element with the class ripple and appending it to the button.

js
const element = ref();
function createRippleEffect(event: MouseEvent) {
	if(!element.value) { return; }

	const button = (props.to) ? element.value.$el : element.value;
	if(!button) { return; }

	const circle = document.createElement('span');
	const diameter = Math.max(button.clientWidth, button.clientHeight);
	const radius = diameter / 2;

	circle.style.width = circle.style.height = `${diameter}px`;
	const buttonPosition = button.getBoundingClientRect();
	circle.style.left = `${event.clientX - buttonPosition.left - radius}px`;
	circle.style.top = `${event.clientY - buttonPosition.top - radius}px`;
	circle.classList.add('ripple');

	const ripple = button.getElementsByClassName('ripple')[0];

	if (ripple) {
		ripple.remove();
	}

	button.appendChild(circle);
}

The ripple element is then animated with CSS. The animation is done by setting the transform property to scale(1) and opacity to 0.

This effect needs the button to have a position property set to relative or absolute so that the ripple element can be positioned absolutely, as well as hiding the overflow of the button.

js
<style lang="scss">
.ripple {
	position: absolute;
	border-radius: 50%;
	transform: scale(0);
	animation: ripple 600ms linear;
	background-color: rgba(255, 255, 255, .3);
}

@keyframes ripple {
	to {
		transform: scale(4);
		opacity: 0;
	}
}
</style>

Type declarations

ButtonSize

ts
export enum ButtonSize {
  DEFAULT = 'default',
  SMALL = 'small',
}

ButtonMode

ts
export enum ButtonMode {
  NORMAL = 'normal',
  OUTLINE = 'outline',
  CLEAR = 'clear',
  LINK = 'link',
}

ButtonColor

ts
export enum ButtonColor {
  PRIMARY = 'primary',
  SECONDARY = 'secondary',
  TERTIARY = 'tertiary',
  DANGER = 'danger',
  WARNING = 'warning',
  SUCCESS = 'success',
  LIGHT = 'light',
  MEDIUM = 'medium',
  DARK = 'dark',
}

ComponentSkin

ts
export enum ComponentSkin {
	PANDA = 'panda',
	DESIGN_SYSTEM = 'ds',
}