Skip to content

Instantly share code, notes, and snippets.

@AvocadoVenom
Last active June 25, 2022 11:00
Show Gist options
  • Select an option

  • Save AvocadoVenom/2fa11b082ecb07e61eae90d05099336f to your computer and use it in GitHub Desktop.

Select an option

Save AvocadoVenom/2fa11b082ecb07e61eae90d05099336f to your computer and use it in GitHub Desktop.
Autonomous expandable block content which detects toggle button need
<template>
<div class="block-content">
<transition
@before-enter="onBeforeEnter"
@enter="onEnter"
@after-enter="onAfterEnter"
@before-leave="onBeforeLeave"
@leave="onLeave"
mode="out-in"
>
<div v-if="!isExpanded" class="block-content__preview">
<p ref="preview" v-html="content" />
</div>
<p
v-else
:class="{
'block-content__paragraph': true,
'block-content__paragraph--is-expanded': isExpanded,
}"
v-html="content"
/>
</transition>
<button
v-if="isToggleButtonRequired"
type="button"
class="block-content__button"
aria-label="Toggle button"
@click="isExpanded = !isExpanded"
>
{{ toggleCtaLabel }}
</button>
</div>
</template>
<script lang="ts">
import { computed, defineComponent, onMounted, ref, toRefs } from "vue";
export default defineComponent({
name: "ExpandableBlockContent",
props: {
content: { type: String },
visibleLines: { type: Number, default: 4 },
},
setup(props) {
const { visibleLines } = toRefs(props);
// Collapsed state
// Assuming that default line-height is 24px
const LINE_HEIGHT = 24;
const maxHeightCollapsed = computed(() => LINE_HEIGHT * visibleLines.value);
// Expanded state
const isExpanded = ref(false);
// Toggle button
const preview = ref<HTMLElement | null>(null);
onMounted(() => {
const previewHeight = (preview.value ?? {}).clientHeight ?? 0;
isToggleButtonRequired.value = previewHeight > maxHeightCollapsed.value;
});
const isToggleButtonRequired = ref(false);
const toggleCtaLabel = computed(() =>
isExpanded.value ? "Read less" : "Read more"
);
// Animation hooks (omitted to minimize snippet length)
const onBeforeEnter = (el: Element) => { /** ... */ };
const onEnter = (el: Element) => { /** ... */ };
const onAfterEnter = (el: Element) => { /** ... */ };
const onBeforeLeave = (el: Element) => { /** ... */ };
const onLeave = (el: Element) => { /** ... */ };
return {
isExpanded,
preview,
isToggleButtonRequired,
toggleCtaLabel,
onBeforeEnter,
onEnter,
onAfterEnter,
onBeforeLeave,
onLeave,
};
},
});
</script>
<style lang="scss" scoped>
/** ... */
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment