I am using Nuxt3 and for some reason, the maxlength="70"
attribute specified in the below HTML input element is not respected (I can type more than 70 characters). Does anyone know why?
<input
type="text"
class="form-control"
id="title"
placeholder="title"
v-model.trim="formData.title"
required
maxlength="70"
aria-describedby="titleCount"
/>
I am able to reproduce this with a minimal production here: https://stackblitz.com/edit/nuxt-starter-kmrpo9?file=app.vue
The full code:
<template>
<section>
<div class="card border-0">
<div class="row g-0">
<div class="col-lg-4"></div>
<div class="col-lg-8">
<main class="card-body">
<form class="mt-3 mt-lg-0" @keydown.enter.prevent="">
<div class="form-floating mb-3">
<input
type="text"
class="form-control"
id="title"
placeholder="title"
v-model.trim="formData.title"
required
maxlength="70"
aria-describedby="titleCount"
/>
<div id="titleCount" class="form-text">
{{ titleLimit - formData.title.length }}
characters remaining
</div>
<label for="title">Title</label>
</div>
</form>
</main>
</div>
</div>
</div>
</section>
</template>
<script setup lang="ts">
const props = defineProps({
post: {
type: Object,
default: () => ({
caption: '',
title: '',
content: '',
source: '',
tags: [],
imageFileName: '',
imagePath: '',
width: null,
height: null,
}),
},
});
const formData = reactive({ ...props.post });
// Limit the number of title characters to 70
const titleLimit = computed(() => {
const limit = 70;
const titleLength = formData.title.length;
return limit - titleLength;
});
</script>
Since you're using v-model.trim="formData.title"
here, you are probably overriding the default behavior of the HTML tag thanks to the power of Vue.
Either remove that one or handle the logic yourself by not allowing the user to type more characters but in Vue, with an @input
checking the length for example.
Here is your example as a working demo.
<template>
<section>
<div class="card border-0">
<div class="row g-0">
<div class="col-lg-4"></div>
<div class="col-lg-8">
<main class="card-body">
<form class="mt-3 mt-lg-0" @keydown.enter.prevent="">
<div class="form-floating mb-3">
<input
type="text"
class="form-control"
id="title"
placeholder="title"
:value="formData.title"
@input.trim="updateIfPossible"
required
maxlength="70"
aria-describedby="titleCount"
/>
<div id="titleCount" class="form-text">
{{ titleLimit }}
characters remaining
</div>
<label for="title">Title</label>
</div>
</form>
</main>
</div>
</div>
</div>
</section>
</template>
<script setup lang="ts">
const props = defineProps({
post: {
type: Object,
default: () => ({
caption: '',
title: '',
content: '',
source: '',
tags: [],
imageFileName: '',
imagePath: '',
width: null,
height: null,
}),
},
});
const formData = reactive({ ...props.post });
// Limit the number of title characters to 70
const titleLimit = computed(() => {
const limit = 70;
const titleLength = formData.title.trim().length;
return limit - titleLength;
})
function updateIfPossible(e) {
if (formData.title.trim().length > 70) return
formData.title = e.target.value
}
</script>