Immediate client side validation - like used from modern JS-based-UI-Frameworks like React, Angular or Vue - on all input-components (triggered by keyup- respectively change-events depending on component) and CommandButton only enabled after successful CSV of all input-components relevant due to process-attribute.
<style type="text/css">
    body .ui-panelgrid .ui-panelgrid-cell {
        padding: 0.5rem;
    }
    button.ui-state-csv-valid, input.ui-state-csv-valid, .ui-inputfield.ui-state-csv-valid, .ui-selectonemenu.ui-state-csv-valid {
        border-left-color: green !important; /* !important to override border-color set by ui-state-focus */
        border-left-style: solid;
        border-left-width: 5px;
    }
    button.ui-state-csv-invalid, input.ui-state-csv-invalid, .ui-inputfield.ui-state-csv-invalid, .ui-selectonemenu.ui-state-csv-invalid {
        border-left-color: red !important; /* !important to override border-color set by ui-state-focus */
        border-left-style: solid;
        border-left-width: 5px;
    }
</style>
<div class="card">
    <h:form>
        <p:messages>
            <p:autoUpdate/>
        </p:messages>
        <p:panelGrid id="gridName" columns="4" layout="flex"
                     columnClasses="col-12 xl:col-3, col-12 xl:col-2, col-12 xl:col-5, col-12 xl:col-2"
                     contentStyleClass="align-items-baseline ui-fluid">
            <p:outputLabel for="name" value="Name (3-50 characters):"/>
            <p:inputText id="name" value="#{validationView.text}" required="true" label="Name">
                <f:validateLength minimum="3" maximum="50"/>
                <p:clientValidator event="keyup" />
            </p:inputText>
            <p:message for="name"/>
            <h:outputText value="#{validationView.text}"/>
        </p:panelGrid>
        <p:panelGrid id="gridNumber" columns="4" layout="flex"
                     columnClasses="col-12 xl:col-3, col-12 xl:col-2, col-12 xl:col-5, col-12 xl:col-2"
                     contentStyleClass="align-items-baseline ui-fluid">
            <p:outputLabel for="number" value="Number:"/>
            <p:inputNumber id="number" value="#{validationView.integer}" label="Number"
                            validateMask="false" required="true">
                <f:validateLongRange minimum="100" maximum="9999" />
                <p:clientValidator event="keyup" />
            </p:inputNumber>
            <p:message for="number"/>
            <h:outputText value="#{validationView.integer}"/>
        </p:panelGrid>
        <p:panelGrid id="gridEverythingElse" columns="4" layout="flex"
                     columnClasses="col-12 xl:col-3, col-12 xl:col-2, col-12 xl:col-5, col-12 xl:col-2"
                     contentStyleClass="align-items-baseline ui-fluid">
            <p:outputLabel for="dd" value="Double (5.5 - 8.5):"/>
            <p:inputText id="dd" value="#{validationView.doubleNumber}"
                            converterMessage="Cannot convert to double." required="true">
                <f:validateDoubleRange minimum="5.5" maximum="8.5"/>
                <p:clientValidator event="keyup" />
            </p:inputText>
            <p:message for="dd"/>
            <h:outputText value="#{validationView.doubleNumber}"/>
            <p:outputLabel for="regex" value="Regex (^[a-zA-Z]+$):"/>
            <p:inputText id="regex" value="#{validationView.regexText}"
                            validatorMessage="Value does not match pattern." required="true">
                <f:validateRegex pattern="^[a-zA-Z]+$"/>
                <p:clientValidator event="keyup" />
            </p:inputText>
            <p:message for="regex"/>
            <h:outputText value="#{validationView.regexText}"/>
            <p:outputLabel for="localDate" value="LocalDate (Java8; PF DatePicker)"/>
            <p:datePicker id="localDate" value="#{validationView.localDate}" pattern="MM/dd/yyyy"
                            label="LocalDate (DatePicker)" required="true">
                <p:clientValidator />
            </p:datePicker>
            <p:message for="localDate"/>
            <h:outputText value="#{validationView.localDate}">
                <f:convertDateTime pattern="MM/dd/yyyy" type="localDate"/>
            </h:outputText>
            <p:outputLabel for="@next" value="Select UI-library" />
            <p:selectOneMenu id="selectOneMenu" value="#{validationView.uiLibrary}" required="true">
                <f:selectItem itemLabel="" itemValue="" noSelectionOption="true" />
                <f:selectItem itemLabel="JSF" itemValue="JSF" />
                <f:selectItem itemLabel="Angular" itemValue="Angular" />
                <f:selectItem itemLabel="React" itemValue="React" />
                <f:selectItem itemLabel="Vue" itemValue="Vue" />
                <p:clientValidator />
            </p:selectOneMenu>
            <p:message for="selectOneMenu"/>
            <h:outputText value="#{validationView.uiLibrary}"/>
        </p:panelGrid>
        <p:remoteCommand name="rc" update="gridName gridNumber" process="name number" validateClient="true"/>
        <p:defaultCommand target="btnAjax"/>
        <div class="pt-3">
            <p:commandButton value="Non-Ajax" ajax="false" validateClient="true" enabledByValidateClient="true" styleClass="mr-2" />
            <p:commandButton value="Ajax" id="btnAjax" update="@form" validateClient="true" enabledByValidateClient="true" styleClass="mr-2" />
            <p:commandButton value="Partial (name + number)" update="gridName gridNumber" process="name number" validateClient="true" enabledByValidateClient="true" styleClass="mr-2" />
            <p:commandButton value="Disabled (without CSV)" ajax="false" styleClass="mr-2"/>
            <p:commandButton value="Remote Command" type="button" enabledByValidateClient="true" onclick="rc()" />
        </div>
        <div class="pt-3">
            Simulate server-side modifications:<br/>
            <p:commandButton value="Modify Name + Number" update="gridName gridNumber" process="@this" action="#{validationView.modifyValues()}" styleClass="mr-2" />
            <p:commandButton value="Modify Number" update="gridNumber" process="@this" action="#{validationView.modifyInteger()}" styleClass="mr-2" />
            <p:commandButton value="Clear Values" update="@form" process="@this" action="#{validationView.clearValues()}" />
        </div>
        
    </h:form>
</div>
package org.primefaces.showcase.view.csv;
import java.time.LocalDate;
import java.util.Date;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Named;
@Named
@RequestScoped
public class ValidationView {
    private String text;
    private String color;
    private String description;
    private Integer integer;
    private Double doubleNumber;
    private Double money;
    private String regexText;
    private Date date;
    private Date date2;
    private Date date3;
    private LocalDate localDate;
    private LocalDate localDate2;
    private LocalDate localDate3;
    private String uiLibrary;
    public String getText() {
        return text;
    }
    public void setText(String text) {
        this.text = text;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public Integer getInteger() {
        return integer;
    }
    public void setInteger(Integer integer) {
        this.integer = integer;
    }
    public Double getDoubleNumber() {
        return doubleNumber;
    }
    public void setDoubleNumber(Double doubleNumber) {
        this.doubleNumber = doubleNumber;
    }
    public Double getMoney() {
        return money;
    }
    public void setMoney(Double money) {
        this.money = money;
    }
    public String getRegexText() {
        return regexText;
    }
    public void setRegexText(String regexText) {
        this.regexText = regexText;
    }
    public Date getDate() {
        return date;
    }
    public void setDate(Date date) {
        this.date = date;
    }
    public Date getDate2() {
        return date2;
    }
    public void setDate2(Date date) {
        this.date2 = date;
    }
    public Date getDate3() {
        return date3;
    }
    public void setDate3(Date date) {
        this.date3 = date;
    }
    public LocalDate getLocalDate() {
        return localDate;
    }
    public void setLocalDate(LocalDate localDate) {
        this.localDate = localDate;
    }
    public LocalDate getLocalDate2() {
        return localDate2;
    }
    public void setLocalDate2(LocalDate localDate) {
        this.localDate2 = localDate;
    }
    public LocalDate getLocalDate3() {
        return localDate3;
    }
    public void setLocalDate3(LocalDate localDate) {
        this.localDate3 = localDate;
    }
    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }
    public String getUiLibrary() {
        return uiLibrary;
    }
    public void setUiLibrary(String uiLibrary) {
        this.uiLibrary = uiLibrary;
    }
    public void modifyValues() {
        setText("Mike");
        setInteger(123);
    }
    public void modifyInteger() {
        setInteger(456);
    }
    public void clearValues() {
        setText(null);
        setInteger(null);
        setDoubleNumber(null);
    }
}