title: How to style a table cell in JavaFX2 using CSS (without removing hover/selection etc.)
body: <p>I'm trying to style individual table cells in an JavaFX2 <code>TableView</code> (to indicate that a table cell value is changed, contains an error, etc). To achieve this, I have created a custom <code>TableCell</code> that sets the proper CSS class, based on it's content.</p>
  
  <p>This works to some degree, but the problem is that I now lose all effects, the hover, the selection color gradient etc. (i.e. the pseudo classes). </p>
  
  <p><strong>How can I style a table cell using CSS, without requiring re-defining all the possible combinations of pseudo-classes?</strong></p>
  
  <p>I've read  <a href="https://stackoverflow.com/questions/13697115/javafx-tableview-colors">this answer</a> but the solution does not work for me. If I set <code>-fx-control-inner-background</code> to the background color I want, I get hover and selection color like I want, <em>but the initial color is transparent</em>, which is obviously not what I want (I have commented out the attempts in the CSS below, you can uncomment and try for yourself). If you can explain why, and provide a solution, I'd be happy to accept that.</p>
  
  <p>I've also seen <a href="https://stackoverflow.com/questions/14781861/javafx-2-2-styling-a-table-cell-and-handling-row-pseudo-classes-hover-select">this answer</a>, but I really don't want to crate duplicate definitions for all the pseudo-classes (besides, it only seems to work with row selection).</p>
  
  <p>Below is an SSCCE that demonstrates the issue.</p>
  
  <p>Screen shot (this looks like what I want, except the hover and selection doesn't work):</p>
  
  <p><img src="https://i.stack.imgur.com/fp7rT.png" alt="TableView showing modified and error cells"></p>
  
  <p>TableViewSample.java (based on <a href="http://docs.oracle.com/javafx/2/ui_controls/table-view.htm" rel="nofollow noreferrer">Table View tutorial code</a>):</p>
  
  <pre><code>import javafx.application.Application;
  import javafx.beans.property.SimpleStringProperty;
  import javafx.collections.FXCollections;
  import javafx.collections.ObservableList;
  import javafx.geometry.Insets;
  import javafx.scene.Group;
  import javafx.scene.Scene;
  import javafx.scene.control.Label;
  import javafx.scene.control.SelectionMode;
  import javafx.scene.control.TableCell;
  import javafx.scene.control.TableColumn;
  import javafx.scene.control.TableView;
  import javafx.scene.control.cell.PropertyValueFactory;
  import javafx.scene.layout.VBox;
  import javafx.scene.text.Font;
  import javafx.stage.Stage;
  import javafx.util.Callback;
  
  public class TableViewSample extends Application {
  
      public static final String CSS_ORIGINAL = "cell-renderer-original";
      public static final String CSS_CHANGED = "cell-renderer-changed";
      public static final String CSS_ERROR = "cell-renderer-error";
      public static final String CSS_ERROR_AND_CHANGED = "cell-renderer-error-and-changed";
  
      private TableView&lt;Person&gt; table = new TableView&lt;&gt;();
      private final ObservableList&lt;Person&gt; data =
              FXCollections.observableArrayList(
                      new Person("Jacob", "Smith", "jacob.smith@example.com"),
                      new Person("Isabella", "Johnson", "isabella.johnson@example.com"),
                      new Person("Ethan", "Williams", "ethan.williams@example.com"),
                      new Person("Emma", "Jones", "emma.jones@example.com"),
                      new Person("Michael", "Brown", "michael.brown@example.com")
              );
  
      public static void main(String[] args) {
          launch(args);
      }
  
      @Override
      public void start(Stage stage) {
          Scene scene = new Scene(new Group());
          stage.setTitle("Table View Sample");
          stage.setWidth(450);
          stage.setHeight(500);
  
          Label label = new Label("Address Book");
          label.setFont(new Font("Arial", 20));
  
          table.setEditable(true);
  
          // Cell selection only (I need this)
          table.getSelectionModel().setCellSelectionEnabled(true);
          table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
  
          TableColumn&lt;Person, String&gt; firstNameCol = new TableColumn&lt;&gt;("First Name");
          firstNameCol.setMinWidth(100);
          firstNameCol.setCellValueFactory(new PropertyValueFactory&lt;Person, String&gt;("firstName"));
  
          TableColumn&lt;Person, String&gt; lastNameCol = new TableColumn&lt;&gt;("Last Name");
          lastNameCol.setMinWidth(100);
          lastNameCol.setCellValueFactory(new PropertyValueFactory&lt;Person, String&gt;("lastName"));
  
          TableColumn&lt;Person, String&gt; emailCol = new TableColumn&lt;&gt;("Email");
          emailCol.setMinWidth(200);
          emailCol.setCellValueFactory(new PropertyValueFactory&lt;Person, String&gt;("email"));
  
          // Install custom cell renderer
          emailCol.setCellFactory(new Callback&lt;TableColumn&lt;Person, String&gt;, TableCell&lt;Person, String&gt;&gt;() {
              @Override public TableCell&lt;Person, String&gt; call(final TableColumn&lt;Person, String&gt; personStringTableColumn) {
                  return new BackgroundTableCell();
              }
          });
  
          table.setItems(data);
          table.getColumns().addAll(firstNameCol, lastNameCol, emailCol);
  
          VBox vbox = new VBox();
          vbox.setSpacing(5);
          vbox.setPadding(new Insets(10, 0, 0, 10));
          vbox.getChildren().addAll(label, table);
  
          ((Group) scene.getRoot()).getChildren().addAll(vbox);
  
          scene.getStylesheets().add(getClass().getResource("/my.css").toExternalForm());
  
          stage.setScene(scene);
          stage.show();
      }
  
      public static class Person {
  
          private final SimpleStringProperty firstName;
          private final SimpleStringProperty lastName;
          private final SimpleStringProperty email;
  
          private Person(String fName, String lName, String email) {
              this.firstName = new SimpleStringProperty(fName);
              this.lastName = new SimpleStringProperty(lName);
              this.email = new SimpleStringProperty(email);
          }
  
          public String getFirstName() {
              return firstName.get();
          }
  
          public void setFirstName(String fName) {
              firstName.set(fName);
          }
  
          public String getLastName() {
              return lastName.get();
          }
  
          public void setLastName(String fName) {
              lastName.set(fName);
          }
  
          public String getEmail() {
              return email.get();
          }
  
          public void setEmail(String fName) {
              email.set(fName);
          }
      }
  
      // My custom background cell renderer
      private static class BackgroundTableCell extends TableCell&lt;Person, String&gt; {
          @Override protected void updateItem(final String item, final boolean empty) {
              super.updateItem(item, empty);
  
              setText(empty ? "" : item);
  
              getStyleClass().removeAll(CSS_ORIGINAL, CSS_CHANGED, CSS_ERROR, CSS_ERROR_AND_CHANGED);
              updateStyles(empty ? null : item);
          }
  
          private void updateStyles(String item) {
              if (item == null) {
                  return;
              }
  
              if (item.startsWith("i") || item.startsWith("j")) {
                  getStyleClass().add(CSS_CHANGED);
              }
              else if (item.startsWith("e")) {
                  getStyleClass().add(CSS_ERROR);
              }
              else if (item.startsWith("m")) {
                  getStyleClass().add(CSS_ERROR_AND_CHANGED);
              }
          }
      }
  }
  </code></pre>
  
  <p>my.css:</p>
  
  <pre><code>.cell-renderer-changed {
      -fx-background-color: rgba(255, 248, 33, .4);
      /*-fx-control-inner-background: rgb(255, 248, 33);*/
      -fx-accent: derive(-fx-control-inner-background, -40%);
      -fx-cell-hover-color: #cce3f4;
      -fx-cell-focus-inner-border: #85b9de;
  }
  
  .cell-renderer-error {
      -fx-background-color: rgba(255, 159, 160, .4);
      /*-fx-control-inner-background: rgb(255, 159, 160);*/
      -fx-accent: derive(-fx-control-inner-background, -40%);
      -fx-cell-hover-color: #cce3f4;
      -fx-cell-focus-inner-border: #85b9de;
  }
  
  .cell-renderer-error-and-changed {
      -fx-background-color: rgba(255, 205, 158, .4);
      /*-fx-control-inner-background: rgb(255, 205, 158);*/
      -fx-accent: derive(-fx-control-inner-background, -40%);
      -fx-cell-hover-color: #cce3f4;
      -fx-cell-focus-inner-border: #85b9de;
  }
  </code></pre>