Skip to content
ts
import Textarea from '~/ui/Textarea.vue'

Textarea ​

Textareas are input blocks that enable users to write formatted text (format: Markdown). These blocks are used throughout the Funkwhale interface for entering item descriptions, moderation notes, and custom notifications.

ts
const {
  charLimit = Infinity,
  placeholder = '',
  initialLines = 3,
  maxBlockSize,
  uiSunken = useContext().value.uiSunken ?? undefined,
  ...props
} = defineProps<WithAttributes<{
  class: {
    justify?: 'justify-start'
  }
  label?: string
  placeholder?: string
  charLimit?: number
  initialLines?: number | string
  /** Caps the textarea's rendered height, scrolling internally instead of growing forever. The toolbar stays outside this area. */
  maxBlockSize?: string
  /** Text shown in the markdown preview instead of the raw editable value, e.g. with template tokens substituted. Editing always acts on the raw value. */
  previewText?: string
  autofocus?: boolean
  required?: boolean
  disabled?: boolean
  uiSunken?: boolean
}>>()
ts
const model = defineModel<string>({ required: true })

Create a textarea and attach its input to a value using a v-model of type string (required):

ts
const text = ref('# Funkwhale\n\n- Design system')
template
<Textarea v-model="text" />

Add a label ​

template
<Spacer />
  <template #label>
    About my music
    <Link href="/" class="color-primary-solid shape-circle" ui-block-size="24">
      <Icon icon="bi:info-lg" />
    </Link>
    <span style="color:red;">(required)</span>
  </template>
</Textarea>

If you just have a string, we have a convenience prop, so instead you can write:

template
<Spacer />
<Textarea v-model="text" label="About my music" />

Note that the label text sits atop of the upper end of the component. This way, you can define the distance between baselines (the vertical rhythm) with spacers or gaps.

Add a placeholder ​

template
<Textarea
  v-model="text"
  placeholder="Describe this track here…"
/>

Limit the number of characters ​

You can set the maximum length (in characters) that a user can enter in a textarea by passing a charLimit prop.

template
<Textarea v-model="text" :charLimit="20" />

Caveats

  • You can still set the model longer than allowed by changing it via a script or another Textarea
  • A line break counts as one character, which may confuse users
  • The character counting algorithm has not been tested on non-Latin based languages
  • Make sure to inform the user beforehand so they know what error to expect (A11y).

Set the initial height ​

Specify the number of lines with the initial-lines prop (the default is 5):

template
<Textarea v-model="text" initial-lines="1" />

Autofocus ​

If you add the autofocus attribute, the text input field will receive focus as soon as it is rendered on the page. Make sure to only add this prop to a single component per page!

Require this form to be filled before submitting ​

The required attribute prevents the submit button of this form.

Make sure to also add an indicator such as the text "required" or a star to prevent confusion.

See mdn on the required attribute if you want to know more.

Additional attributes ​

Any prop that is not declared in the Props type will be added to the <textarea> element directly. See mdn on textarea attributes here. Examples: autocomplete, cols, minlength, readonly, wrap, disabled etc.

Add custom toolbar items ​

By default, there are text formatting buttons and a 'preview' toggle button in the toolbar. You can add custom content there by adding them into the default slot. They will be drawn before the preview button.

template
<Textarea v-model="text">
  <Spacer no-size grow />
  <Button
    v-if="text !== ''"
    @click.prevent="reset()"
  >
    <Icon icon="bi:arrow-counterclockwise" />
    Reset
  </Button>
</Textarea>

Using this component

A11y Checklist ​

Accessible textarea ​

vue
<Textarea
  v-model="text"
  label="Your message"
/>

Guide: Creating accessible forms

See the complete Form example code

Test this component in isolation against WCAG2 criteria