angular / components

Component infrastructure and Material Design components for Angular
https://material.angular.io
MIT License
24.32k stars 6.73k forks source link

Readonly CSS Styling: MatFormField should reflect css class 'mat-form-field-readonly' similar to 'mat-form-field-disabled' #15809

Open gerhard17 opened 5 years ago

gerhard17 commented 5 years ago

Please describe the feature you would like to request.

The MatFormField component reflects a disabled MatInput directive via a dynamic css class 'mat-form-field-disabled'.

I suggest to implement a dynamic css class 'mat-form-field-readonly' similar to 'mat-form-field-disabled' which reflects the readonly state of the MatInput directive.

What is the use-case or motivation for this proposal?

My proposal would support better css styling. Eg. styling the child 'mat-form-field-underline' of the MatFormField (which is not a dom child of the MatInput directive).

Is there anything else we should know?

No special css styling is required to be implemented by you. Only the possibility to implement one by myself.

Temporary Workaround

Helper directive (ts):

import { Directive, Input, HostBinding } from '@angular/core';
import { MatFormField, MatInput } from '@angular/material';

/* Workaround to provide css class 'mat-form-field-readonly' similiar to 'mat-form-field-disabled'. 
 * Example Usage:
 *  <mat-form-field provideReadonly>
 *      <input matInput placeholder="Readonly Input" readonly="true" value="Some Value">
 *  </mat-form-field>
 */
@Directive({
    selector: 'mat-form-field[provideReadonly]',
    host: {
        '[class.mat-form-field-readonly]': 'isReadonlyInput()'
    }
})
export class ProvideMatFormFieldReadonlyDirective {
    constructor(private _matFormField: MatFormField) { }

    public isReadonlyInput(): boolean {
        const ctrl = this._matFormField._control;
        if (ctrl instanceof MatInput) {
            return ctrl.readonly;
        }
        return false;
    }
}

The directive must be assigned explicitly (html):

<mat-form-field provideReadonly>
    <input matInput placeholder="Readonly Input" readonly="true" value="Some Value">
</mat-form-field>

Which can be styled for example (css):

/* mat-form-field / matInput - readonly support */
.mat-form-field-appearance-legacy.mat-form-field-readonly .mat-form-field-underline {
    background-color: rgba(127, 127, 127, 0.25);
}

Thank You!

sladewasinger commented 5 years ago

This would be a great feature to have.

JulienCabanes commented 5 years ago

I needed this today, thank you for the workaround directive! 👌

AbdulRehman3 commented 5 years ago

I have achieved this way

Thanks to @gerhard17

<!-- form.component.html -->
<mat-form-field floatLabel="never" [ngClass]="{'mat-form-field-readonly':!selection.isSelected(row)}">
    <span matPrefix>$&nbsp;</span>
    <input 
        matInput 
        placeholder="Discount" 
        formControlName="discountRate" 
        required
        [readonly]="!selection.isSelected(row)"
    >
</mat-form-field>
devversion commented 4 years ago

The problem here is that the form-field technically doesn't care about the readonly state of controls. In fact, the form-field deals with abstract form controls and doesn't even known whether form controls support a readonly state or not.

If we'd want to toggle a class on the form-field for more convenience, then this would require us to proxy it through MatFormFieldControl (might be breaking). That might be confusing, and other control authors would ask for other states to be reflected too.

Generally I think this is a good feature request, but maybe it should be more generic so that individual controls (like matInput) can toggle classes on the form-field for improved styling. That might be generally useful for custom controls.

devversion commented 4 years ago

Also cc. @mmalerba for thoughts on this.

gerhard17 commented 4 years ago

@devversion : Of course a real solution should be more generic. But the most common case needed to support readonly state are text input fields. For this case my workaround was made for. A more general built-in solution would be usefull and wellcomed! :-)

mmalerba commented 4 years ago

Generally I think this is a good feature request, but maybe it should be more generic so that individual controls (like matInput) can toggle classes on the form-field for improved styling. That might be generally useful for custom controls.

Yeah, I agree with that, would be a useful addition.

JohnYoungers commented 4 years ago

@devversion - with the upcoming work around adding types around ReactiveForms, is there any reason the 'ReadOnly' concept can't be added to AbstractControl similar to enabled/disabled?

Currently we have a lot of controls that are 'disabled', but really they should be 'readonly': styled more inline with that specification (https://material.io/components/text-fields#input-types), and should show up in .value (opposed to needing to call getRawValue()

infacto commented 2 years ago

With upcoming CSS feature :has(selector)

we could use

mat-form-field:has(input[readonly]) {
  opacity: 0.5;
}

(Not tested, maybe wrong use.) This is not yet supported. So we have to push this feature. ...


I don't like the read-only text info solution as described in https://material.io/components/text-fields#input-types ("Read-only fields" unfortunately no id for hashtag nav.)

image

You have to translate it. And I would use the placeholder, since it's only displayed when value is empty. Another solution could be using tooltips. But this is maybe not mobile fiendly.

The disabled style is just half opacity, right? I would expect the same style for readonly.

image

Passing readonly class to mat-form-field can really be a breaking change and confusing?

Anyway, currently I'm not sure what workaround I'll use. Maybe a directive? To manage the class name and input attribute readonly, etc. 'll see...

Btw. note that the readonly attribute can only be added to text controls. No other controls like checkboxes. In this case use disabled. I just read this: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/readonly (see the "Note" info box in english language.)

jrkey commented 2 years ago

I think it is important to understand that changing a read-only (or even a disabled) input to a shade of gray is a poor solution. Just because the value is read-only doesn't mean it doesn't need to be equally as legible as normal inputs. Gray text on a white background generally provides poor visual contrast making the text harder to read/view.

A read-only input should display as normal black text so it continues to be easy to see/read. The readonly input should display the label (bolded black text) and the associated value (regular black text) so they look like normal text that doesn't provide any interaction (no icons, no drop-down arrows, background, underline, etc.).

princehorn commented 1 year ago

Moin,

why not simply combine the disabled state of the mat-form-field control with the readonly state of the input element. Then only style the text color of the input element according to gain a good visual contrast.

This solution achieves:

  1. good readability
  2. visually and functionally disabled form field (including the underline styles) and e.g. clear button (mat-suffix)
  3. no further adjustments to the interface of MatFormFieldControl
<mat-form-field>
    <mat-label>My Label</mat-label>
    <input
        type="text"
        matInput
        formControlName="testReadonlyInput"
        [readonly]="form.controls.testReadonlyInput.disabled"
    >
</mat-form-field>
.mat-input-element:disabled[readonly] {
    color: currentColor;
}
readonly-mat-form-field-and-input

Munter bleiben ✌️