1

I would like to migrate my Vue 2 functional component to Vue 3. I read their official docs but don't understand it.

I have for example this component:

module.exports = (name, path, ariaLabel) => `<template functional>
  <div
    :class="['main-${name}', props.width ? 'default-width' : undefined]"
  >
  <span  v-if="title">${title}</span>
  <span> hello </span>
  </div>
</template>

<script>
export default {
  name: 'test-${name}',
  props: {
    width: {
      type: [Number, String],
      default: null
    },
    title: {
      type: String,
      required: false
    },
  }
}
</script>
<style src="./style.css"/>
`

I got this far converting to Vue 3:

import { h } from 'vue'

const MyComponent = (props, context) => {
    return h(`div${props.name}`, context.attrs, context.slots)
}

MyComponent.props = {
    width: {
        type: [Number, String],
        default: null
    },
    title: {
        type: String,
        required: false
    },
}

import styles from './style.css';

export default MyComponent;

How do I properly import CSS? How would I add the nested span and the classes?

0

1 Answer 1

4

Styles

External CSS files can be imported into the file, and those styles will automatically be applied to the component:

import './MyComponent.css'

props.name

You're using props.name, which isn't declared, so make sure to add it to props:

MyComponent.props = {
  //...
  name: {
    type: String,
    required: true,
  },
}

h() Arguments

  1. The 2nd argument of h() is an object of attributes, which includes class, so you would pass the multiple class names under the class key.
  2. The 3rd argument of h() can be a string, slots, or an array of child elements, which are also created with h(), so you could nest the <span>s by passing them in an array.
import { h } from 'vue'

const MyComponent = ({ name, width, title }) =>
  h(
    'div',

    // 1
    {
      class: `main-${name} ${width && 'default-width'}`
    },

    // 2
    [
      title && h('span', null, title), // conditional on `title`
      h('span', null, ' hello ')
    ]
  )

demo

JSX

Projects generated with Vue CLI also support JSX out of the box, which might be more straightforward given how close it is to the original HTML. Here's the equivalent of the h() calls above:

const MyComponent = ({ name, width, title }) =>
  <div class={`main-${name} ${width && 'default-width'}`}>
    {title && <span>{title}</span>}
    <span> hello </span>
  </div>
Sign up to request clarification or add additional context in comments.

3 Comments

@DouglasGaskell In Vue 3, the context argument of render includes slots, which contains the children nodes. You can pass that along in createElement('div', null, context.slots) to forward the children.
awesome solution! Do you know though how to type Functional Component in a non hacky way? I found FunctionalComponent type which is great but I can't find a recommended way to type Props or Attrs without using as
nvm found it! I can pass a type into the FunctionalComponent Generic. Gonna post another comment with the solution soon

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.