Skip to content

Instantly share code, notes, and snippets.

@Jamiewarb
Created August 4, 2025 14:24
Show Gist options
  • Save Jamiewarb/d6d7c701146cd4ab8626f2d136c85719 to your computer and use it in GitHub Desktop.
Save Jamiewarb/d6d7c701146cd4ab8626f2d136c85719 to your computer and use it in GitHub Desktop.
Example ticker/marquee
<script setup lang="ts">
import { baseTickerVariants } from '.';
export interface TickerProps {
repeat?: number;
items: string[];
size?: NonNullable<Parameters<typeof baseTickerVariants>[0]>['size'];
reversed?: boolean;
}
const props = withDefaults(defineProps<TickerProps>(), {
repeat: 10,
size: 'large',
reversed: false,
});
// Calculates the speed to be 'roughly' the same for all tickers based on the amount of characters
const speed = computed(() => {
const amountOfCharacters = props.items.reduce((acc, item) => acc + item.length, 0);
const amountOfSpaces = props.items.length - 1;
const speedPerCharacter = props.size === 'small' ? 200 : 350;
return (amountOfCharacters + (amountOfSpaces * 2.5)) * speedPerCharacter;
});
</script>
<template>
<div>
<div
v-if="size === 'large'"
:class="baseTickerVariants({ size, reversed: !reversed, mobile: true })"
:style="{
'--c-ticker-animation-duration': `${speed}ms`,
}"
>
<div v-for="index in repeat" :key="index" class="c-ticker__content flex flex-row flex-nowrap items-center">
<div v-for="item of items" :key="item" class="c-ticker__item">
{{ item }}
</div>
</div>
</div>
<div
:class="baseTickerVariants({ size, reversed })"
:style="{
'--c-ticker-animation-duration': `${speed}ms`,
}"
>
<div v-for="index in repeat" :key="index" class="c-ticker__content flex flex-row flex-nowrap items-center">
<div v-for="item of items" :key="item" class="c-ticker__item">
{{ item }}
</div>
</div>
</div>
</div>
</template>
<style scoped>
@import '~/assets/css/mixins/_mixins.index.pcss';
.c-ticker {
--animation-direction: normal;
&--large {
--gap: 3.5rem;
color: var(--ticker-large-color);
@mixin h1;
}
&--small {
--gap: 2.5rem;
color: var(--ticker-small-color);
@mixin h3;
}
&--reversed {
--animation-direction: reverse;
}
&--mobile {
margin-bottom: 0.5rem;
@screen tablet-wide {
display: none !important;
}
}
gap: var(--gap);
max-width: 100vw;
display: flex;
overflow: visible;
@keyframes ticker {
0% {
transform: translateX(0);
}
100% {
transform: translateX(calc(-100% - var(--gap)));
}
}
&__content {
animation-name: ticker;
animation-timing-function: linear;
animation-iteration-count: infinite;
animation-direction: var(--animation-direction);
animation-duration: var(--c-ticker-animation-duration);
gap: var(--gap);
}
&__item {
white-space: nowrap;
flex-wrap: nowrap;
text-transform: uppercase;
}
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment