Skip to content

Share ​

Overview ​

The VBsbShare component is a versatile social sharing button group that integrates various social media platforms such as Twitter, Facebook, LinkedIn, WhatsApp, and a copy-to-clipboard functionality. This component allows users to share content across different social networks with ease, offering customizable options for appearance, behavior, and supported platforms.

Usage Examples ​

Basic Example ​

vue
<template>
  <VBsbShare
    :share="['twitter', 'facebook', 'linkedin', 'whatsapp', 'copy']"
    :share-options="{ text: 'Check out this amazing content!', url: 'http://example.com' }"
    :window-features="{ width: 600, height: 400, top: 100, left: 100 }"
  />
</template>

<script setup>
import VBsbShare from '@/components/VBsbShare.vue'
</script>

Customized Button Styles Example ​

You can customize the appearance of the buttons by providing different values for variant, density, and color props.

vue
<template>
  <VBsbShare
    :share="['twitter', 'facebook']"
    :share-options="{ text: 'Learn more about our services', url: 'http://example.com' }"
    :variant="'outlined'"
    :density="'compact'"
    :color="'primary'"
  />
</template>

<script setup>
import VBsbShare from '@/components/VBsbShare.vue'
</script>

Copy-to-Clipboard Only Example ​

You can enable only the copy-to-clipboard functionality without social sharing buttons by adjusting the share prop.

vue
<template>
  <VBsbShare :share="['copy']" :share-options="{ text: 'Copy this important information!' }" />
</template>

<script setup>
import VBsbShare from '@/components/VBsbShare.vue'
</script>

API ​

Props ​

PropTypeDefaultDescription
shareArray<'twitter', 'facebook', 'linkedin', 'whatsapp', 'copy'>['twitter', 'facebook', 'linkedin', 'whatsapp', 'copy']Specifies the social media platforms to display as sharing options.
windowFeaturesObject (of type WindowFeatures){ width: 600, height: 400, top: 100, left: 100 }Specifies the features of the popup window when sharing (width, height, top, left position).
shareOptionsObject (of type ShareOptions){ text: '', url: '', number: '' }Defines options related to the shared content, such as the text, URL, and (for WhatsApp) a phone number.
useNativeBehaviorBooleanfalseDetermines whether to use the native behavior of the social share platform (when applicable).
variant'flat' | 'text' | 'elevated' | 'tonal' | 'outlined' | 'plain'undefinedDefines the style of the Vuetify buttons (e.g., flat, outlined, elevated).
density'default' | 'comfortable' | 'compact'undefinedControls the density (size and spacing) of the buttons (default, comfortable, compact).
colorStringundefinedSpecifies the color of the buttons, which corresponds to Vuetify’s color schemes (e.g., primary, secondary, etc.).

Emits ​

The component does not emit any custom events.

Exposes ​

The component does not expose any methods or variables to parent components.

Types ​

Share ​

ts
export type Share = 'twitter' | 'facebook' | 'linkedin' | 'whatsapp' | 'copy'

This type defines the available social sharing platforms.

WindowFeatures ​

ts
export type WindowFeatures = {
  width: number
  height: number
  top: number
  left: number
}

This type defines the attributes for controlling the pop-up window features when sharing on social media.

ShareOptions ​

ts
export type ShareOptions = {
  text?: string // Text to share
  url: string // URL to share
  via?: string // Optional: account to credit (for Twitter)
  hashtags?: string[] // Optional: hashtags to include (for Twitter)
  number: string // Optional: phone number (for WhatsApp)
  quote?: string // Optional: quote to include (for Facebook)
}

This type defines the options related to the shared content, including text, URL, and platform-specific details (e.g., via for Twitter, number for WhatsApp).

Source ​

  1. Install Dependencies
ps
npm install vue-socials
  1. Create component and unit test.
Component
vue
<template>
  <v-defaults-provider
    :defaults="{ VBtn: { variant: props.variant, density: props.density, color: props.color } }"
  >
    <STwitter
      v-if="props.share.includes('twitter')"
      :window-features="windowFeatures"
      :useNativeBehavior="useNativeBehavior"
      :share-options="shareOptions"
    >
      <v-btn data-cy="v-bsb-share-twitter" icon="$mdiTwitter" />
    </STwitter>

    <SFacebook
      v-if="props.share.includes('facebook')"
      :window-features="windowFeatures"
      :useNativeBehavior="useNativeBehavior"
      :share-options="shareOptions"
    >
      <v-btn data-cy="v-bsb-share-facebook" icon="$mdiFacebook" />
    </SFacebook>

    <SLinkedIn
      v-if="props.share.includes('linkedin')"
      :window-features="windowFeatures"
      :useNativeBehavior="useNativeBehavior"
      :share-options="shareOptions"
    >
      <v-btn data-cy="v-bsb-share-linkedin" icon="$mdiLinkedin" />
    </SLinkedIn>

    <SWhatsApp
      v-if="props.share.includes('whatsapp')"
      :window-features="windowFeatures"
      :useNativeBehavior="useNativeBehavior"
      :share-options="shareOptions"
    >
      <v-btn data-cy="v-bsb-share-whatsapp" icon="$mdiWhatsapp" />
    </SWhatsApp>
    <v-btn
      v-if="props.share.includes('copy')"
      data-cy="v-bsb-share-copy"
      icon="$mdiContentCopy"
      @click="copyToClipboard"
    />
  </v-defaults-provider>
</template>

<script setup lang="ts">
import { STwitter, SFacebook, SLinkedIn, SWhatsApp } from 'vue-socials'

export type Share = 'twitter' | 'facebook' | 'linkedin' | 'whatsapp' | 'copy'

export type WindowFeatures = {
  width: number
  height: number
  top: number
  left: number
}

export type ShareOptions = {
  text?: string
  url: string
  via?: string
  hashtags?: string[]
  number: string
  quote?: string
}

const props = defineProps({
  share: {
    type: Array as PropType<Share[]>,
    default: () => ['twitter', 'facebook', 'linkedin', 'whatsapp', 'copy'],
  },
  windowFeatures: {
    type: Object as PropType<WindowFeatures>,
    default: () => ({ url: '' }),
  },
  shareOptions: {
    type: Object as PropType<ShareOptions>,
    default: () => ({ number: '' }),
  },
  useNativeBehavior: {
    type: Boolean,
    default: false,
  },
  variant: {
    type: String as PropType<
      'flat' | 'text' | 'elevated' | 'tonal' | 'outlined' | 'plain' | undefined
    >,
    default: undefined,
  },
  density: {
    type: String as PropType<'default' | 'comfortable' | 'compact' | undefined>,
    default: undefined,
  },
  color: {
    type: String as PropType<string | undefined>,
    default: undefined,
  },
})

const copyToClipboard = () => {
  if (navigator.clipboard) {
    navigator.clipboard
      .writeText(props.shareOptions.text || '')
      .then(() => console.log('Copied to clipboard'))
      .catch((err) => console.error('Error copying to clipboard', err))
  } else {
    const el = document.createElement('textarea')
    el.value = props.shareOptions.text || ''
    document.body.appendChild(el)
    el.select()
    document.execCommand('copy')
    document.body.removeChild(el)
  }
}
</script>
Test
ts
import { mount, VueWrapper } from '@vue/test-utils'
import { describe, it, expect, beforeEach, vi } from 'vitest'
import VBsbShare from '../VBsbShare.vue'
import vuetify from '../../plugins/vuetify'

vi.mock('navigator.clipboard', () => ({
  writeText: vi.fn(() => Promise.resolve()),
}))

describe('VBsbShare.vue', () => {
  let wrapper: VueWrapper

  beforeEach(() => {
    wrapper = mount(VBsbShare, {
      global: {
        plugins: [vuetify],
      },
      props: {
        share: ['twitter', 'facebook', 'linkedin', 'whatsapp', 'copy'],
        windowFeatures: { width: 600, height: 400, top: 100, left: 100 },
        shareOptions: { text: 'Share this text', url: 'http://example.com', number: '123' },
        useNativeBehavior: false,
        variant: 'flat',
        density: 'default',
        color: 'primary',
      },
    })
  })

  it('renders the correct number of share buttons', () => {
    const buttons = wrapper.findAll('button')
    expect(buttons.length).toBe(5)
  })

  it('renders the Twitter share button', () => {
    const twitterBtn = wrapper.find('button[data-cy="v-bsb-share-twitter"]')
    expect(twitterBtn.exists()).toBe(true)
  })

  it('renders the Facebook share button', () => {
    const facebookBtn = wrapper.find('button[data-cy="v-bsb-share-facebook"]')
    expect(facebookBtn.exists()).toBe(true)
  })

  it('renders the LinkedIn share button', () => {
    const linkedInBtn = wrapper.find('button[data-cy="v-bsb-share-linkedin"]')
    expect(linkedInBtn.exists()).toBe(true)
  })

  it('renders the WhatsApp share button', () => {
    const whatsappBtn = wrapper.find('button[data-cy="v-bsb-share-whatsapp"]')
    expect(whatsappBtn.exists()).toBe(true)
  })

  it('renders the Copy button', () => {
    const copyBtn = wrapper.find('button[data-cy="v-bsb-share-copy"]')
    expect(copyBtn.exists()).toBe(true)
  })

  it('does not render social buttons when they are not in the share prop', async () => {
    await wrapper.setProps({ share: ['copy'] })

    const twitterBtn = wrapper.find('button[data-cy="v-bsb-share-twitter"]')
    const copyBtn = wrapper.find('button[data-cy="v-bsb-share-copy"]')

    expect(twitterBtn.exists()).toBe(false)
    expect(copyBtn.exists()).toBe(true)
  })
})