Basics

Custom Element

js
import {
  TypeField,
  NameField,
  LabelField,
  InfoField,
  DescriptionField,
  ContentField,
  BeforeField,
  BetweenField,
  AfterField,
  SizeField,
  ColumnsField,
  ConditionsField,
} from '@vueform/builder'

import ShareUrlField from './path/to/ShareUrlField.js'

export default {
  categories: [],
  elements: [
    'facebookShare',
  ],
  element: {
    types: {
      facebookShare: {
        label: 'Facebook share',
        description: 'Facebook share button',
        icon: 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M400 32H48A48 48 0 0 0 0 80v352a48 48 0 0 0 48 48h137.25V327.69h-63V256h63v-54.64c0-62.15 37-96.48 93.67-96.48 27.14 0 55.52 4.84 55.52 4.84v61h-31.27c-30.81 0-40.42 19.12-40.42 38.73V256h68.78l-11 71.69h-57.78V480H400a48 48 0 0 0 48-48V80a48 48 0 0 0-48-48z"/></svg>',
        // category: 'static',
        schema: {
          type: 'facebook-share',
        },
        sections: {
          properties: {
            name: 'properties',
            label: 'Properties',
            fields: {
              type: { type: TypeField },
              name: { type: NameField },
              label: { type: LabelField },
              tooltip: { type: InfoField },
              description: { type: DescriptionField },
            },
          },
          options: {
            name: 'options',
            label: 'Options',
            fields: {
              url: { type: ShareUrlField },
            },
          },
          decorators: {
            name: 'decorators',
            label: 'Decorators',
            fields: {
              before: { type: BeforeField },
              between: { type: BetweenField },
              after: { type: AfterField },
            },
          },
          layout: {
            name: 'layout',
            label: 'Layout',
            fields: {
              size: { type: SizeField },
              columns: { type: ColumnsField },
            },
          },
          conditions: {
            name: 'conditions',
            label: 'Conditions',
            fields: {
              conditions: { type: ConditionsField },
            },
          },
        },
      },
      separators: {
        properties: [
          ['type', 'name'],
          ['label', 'tooltip'],
          ['description'],
        ],
        layout: [
          ['size'],
          ['columns'],
        ],
      },
    }
  }
}
js
import FacebookShareElement from './path/to/FacebookShareElement.vue'

export default {
  elements: [
    FacebookShareElement,
  ],
  // ...
}
vue
<template>
  <ElementLayout>
    <template #element>
      <div
        :class="classes.button"
        @click="handleClick"
      >
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M400 32H48A48 48 0 0 0 0 80v352a48 48 0 0 0 48 48h137.25V327.69h-63V256h63v-54.64c0-62.15 37-96.48 93.67-96.48 27.14 0 55.52 4.84 55.52 4.84v61h-31.27c-30.81 0-40.42 19.12-40.42 38.73V256h68.78l-11 71.69h-57.78V480H400a48 48 0 0 0 48-48V80a48 48 0 0 0-48-48z"/></svg>
        Share on Facebook
      </div>
    </template>

    <!-- Default element slots -->
    <template v-for="(component, slot) in elementSlots" #[slot]><slot :name="slot" :el$="el$"><component :is="component" :el$="el$"/></slot></template>
  </ElementLayout>
</template>

<script>
  import { ref, toRefs } from 'vue'
  import VueformElement from '@vueform/vueform/element'

  export default VueformElement({
    name: 'FacebookShareElement',
    props: {
      url: {
        type: String,
        required: false,
        default: null,
      }
    },
  }, {
    setup(props, { element })
    {
      const { url } = toRefs(props)

      // ================ DATA ================

      const defaultClasses = ref({
        container: '',
        button: 'facebook-share-button',
        button_sm: 'facebook-share-button-sm',
        button_md: 'facebook-share-button-md',
        button_lg: 'facebook-share-button-lg',
        $button: (classes, { Size }) => ([
          classes.button,
          classes[`button_${Size}`],
        ])
      })

      // =============== METHODS ==============

      const handleClick = () => {
        alert(!url?.value ? 'No Share URL provided. Open the element config panel in editor mode and provide a Share URL.' : `Share URL:\n\n${url.value}`)
      }

      return {
        defaultClasses,
        handleClick,
      }
    }
  })
</script>

<style lang="scss">
  .facebook-share-button {
    background-color: #4267B2;
    color: #ffffff;
    font-weight: 600;
    display: inline-flex;
    align-items: center;
    justify-content: flex-start;
    border-radius: 0.25rem;
    cursor: pointer;
    transition: background .3s;

    &:hover {
      background-color: #5278c6;
    }

    svg {
      margin-right: 0.375rem;
    }

    &.facebook-share-button-sm {
      font-size: var(--vf-font-size-sm);
      padding: 0.125rem 0.75rem 0.125rem 0.5rem;

      svg {
        width: var(--vf-font-size-sm);
        height: var(--vf-font-size-sm);
      }
    }

    &.facebook-share-button-md {
      font-size: var(--vf-font-size);
      padding: 0.25rem 1rem 0.25rem 0.75rem;

      svg {
        width: var(--vf-font-size);
        height: var(--vf-font-size);
      }
    }

    &.facebook-share-button-lg {
      font-size: var(--vf-font-size-lg);
      padding: 0.375rem 1.25rem 0.375rem 1rem;

      svg {
        width: var(--vf-font-size-lg);
        height: var(--vf-font-size-lg);
      }
    }
  }

</style>
js
import { BaseElementField } from '@vueform/builder'

export default class ShareUrlField extends BaseElementField
{
  name = 'ShareUrlField'

  get schema () {
    return {
      url: {
        type: 'textarea',
        label: 'Share URL',
        columns: { label: 4 },
        floating: false,
        placeholder: 'https://...',
        presets: ['prop-multiline'],
        rows: 1,
        onMounted(el$) {
          setTimeout(() => {
            el$.autosize()
          }, 0)
        },
      },
    }
  }
}
đŸ‘‹ Hire Vueform team for form customizations and developmentLearn more