@@ -149,6 +149,11 @@ export class Textarea implements ComponentInterface {
149149 */
150150 @Prop ( ) disabled = false ;
151151
152+ @Watch ( 'disabled' )
153+ protected disabledChanged ( ) {
154+ this . updateElementInternals ( ) ;
155+ }
156+
152157 /**
153158 * The fill for the item. If `"solid"` the item will have a background. If
154159 * `"outline"` the item will be transparent with a border. Only available when the theme is `"md"`.
@@ -300,16 +305,23 @@ export class Textarea implements ComponentInterface {
300305 if ( nativeInput && nativeInput . value !== value ) {
301306 nativeInput . value = value ;
302307 }
308+ this . updateElementInternals ( ) ;
303309 this . runAutoGrow ( ) ;
304- this . reportValidity ( ) ;
305310 }
306311
307312 /**
308313 * Update validation state when required prop changes
309314 */
310315 @Watch ( 'required' )
311316 protected requiredChanged ( ) {
312- this . reportValidity ( ) ;
317+ // Explicitly update the native element's required attribute to ensure
318+ // browser validation works correctly when required changes dynamically.
319+ // While the template binding should handle this, we need to update it
320+ // synchronously for the browser's validation to recognize the change.
321+ if ( this . nativeInput ) {
322+ this . nativeInput . required = this . required ;
323+ }
324+ this . updateElementInternals ( ) ;
313325 }
314326
315327 /**
@@ -454,8 +466,8 @@ export class Textarea implements ComponentInterface {
454466
455467 componentDidLoad ( ) {
456468 this . originalIonInput = this . ionInput ;
469+ this . updateElementInternals ( ) ;
457470 this . runAutoGrow ( ) ;
458- this . reportValidity ( ) ;
459471 }
460472
461473 componentDidRender ( ) {
@@ -578,11 +590,16 @@ export class Textarea implements ComponentInterface {
578590 }
579591
580592 /**
581- * Reports the validity state to the browser via ElementInternals.
582- * This delegates to the native textarea's built-in validation,
583- * which automatically handles the required prop and other constraints.
593+ * Updates the form value and reports validity state to the browser via
594+ * ElementInternals. This should be called when the component loads, when
595+ * the required prop changes, when the disabled prop changes, and when the value
596+ * changes to ensure the form value stays in sync and validation state is updated.
584597 */
585- private reportValidity ( ) {
598+ private updateElementInternals ( ) {
599+ // Disabled form controls should not be included in form data
600+ // Pass null to setFormValue when disabled to exclude it from form submission
601+ const value = this . disabled ? null : this . getValue ( ) ;
602+ this . internals . setFormValue ( value ) ;
586603 reportValidityToElementInternals ( this . nativeInput , this . internals ) ;
587604 }
588605
@@ -600,11 +617,6 @@ export class Textarea implements ComponentInterface {
600617 } ;
601618
602619 private onChange = ( ev : Event ) => {
603- const input = ev . target as HTMLTextAreaElement | null ;
604- if ( input ) {
605- this . internals . setFormValue ( input . value ) ;
606- this . reportValidity ( ) ;
607- }
608620 this . emitValueChange ( ev ) ;
609621 } ;
610622
0 commit comments