This looks like a perfect time to use a ListView with custom ListCell implementations.
The sample application below shows a very basic application that displays each Person object in a ListView. We will provide our own ListCell so we can control exactly how each Person gets displayed.
I also added a profile photo just for fun :)
import javafx.application.Application; import javafx.beans.property.IntegerProperty; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.geometry.Insets; import javafx.geometry.Orientation; import javafx.geometry.Pos; import javafx.scene.Scene; import javafx.scene.control.Label; import javafx.scene.control.ListCell; import javafx.scene.control.ListView; import javafx.scene.control.Separator; import javafx.scene.image.ImageView; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.stage.Stage; import javafx.util.Callback; public class ListViewDetailSample extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) { // Simple interface VBox root = new VBox(5); root.setPadding(new Insets(10)); root.setAlignment(Pos.CENTER); // First, let's create our list of Persons ObservableList<Person> persons = FXCollections.observableArrayList(); persons.addAll( new Person("John", 34), new Person("Cheyenne", 24), new Person("Micah", 17), new Person("Katelyn", 28) ); // Create a ListView ListView<Person> listView = new ListView<>(); // Bind our list to the ListView listView.setItems(persons); // Now, for the magic. We'll create our own ListCells for the ListView. This allows us to create a custom // layout for each individual cell. For this sample, we'll include a profile picture, the name, and the age. listView.setCellFactory(new Callback<ListView<Person>, ListCell<Person>>() { @Override public ListCell<Person> call(ListView<Person> param) { return new ListCell<Person>() { @Override protected void updateItem(Person person, boolean empty) { super.updateItem(person, empty); // Set any empty cells to show nothing if (person == null || empty) { setText(null); setGraphic(null); } else { // Here we can build our layout. We'll use a HBox for our root container HBox cellRoot = new HBox(5); cellRoot.setAlignment(Pos.CENTER_LEFT); cellRoot.setPadding(new Insets(5)); // Add our profile picture ImageView imgProfilePic = new ImageView("/sample/user.png"); imgProfilePic.setFitHeight(24); imgProfilePic.setFitWidth(24); cellRoot.getChildren().add(imgProfilePic); // A simple Separator between the photo and the details cellRoot.getChildren().add(new Separator(Orientation.VERTICAL)); // Now, create a VBox to hold the name and age VBox vBox = new VBox(5); vBox.setAlignment(Pos.CENTER_LEFT); vBox.setPadding(new Insets(5)); // Add our Person details vBox.getChildren().addAll( new Label("Name: " + person.getName()), new Label("Age: " + person.getAge()) ); // Add our VBox to the cellRoot cellRoot.getChildren().add(vBox); // Finally, set this cell to display our custom layout setGraphic(cellRoot); } } }; } }); // Now, add our ListView to the root layout root.getChildren().add(listView); // Show the Stage primaryStage.setWidth(450); primaryStage.setHeight(400); primaryStage.setScene(new Scene(root)); primaryStage.show(); } } // Simple Person class class Person { private final StringProperty name = new SimpleStringProperty(); private final IntegerProperty age = new SimpleIntegerProperty(); public Person(String name, int age) { this.name.set(name); this.age.set(age); } public String getName() { return name.get(); } public StringProperty nameProperty() { return name; } public void setName(String name) { this.name.set(name); } public int getAge() { return age.get(); } public IntegerProperty ageProperty() { return age; } public void setAge(int age) { this.age.set(age); } }
The Result:

Without ListView:
If you'd prefer not to use a ListView for this display, you can keep another list of your Person displays and bind that to the children list of whichever container you want:
// Create a list to hold our individual Person displays ObservableList<Node> personDisplays = FXCollections.observableArrayList(); // Now add a new PersonDisplay to the list for each Person in the personsList persons.forEach(person -> personDisplays.add(new PersonDisplay(person))); // Bind our personsDisplay list to the children of our root VBox Bindings.bindContent(root.getChildren(), personDisplays);
PersonDisplay class:
class PersonDisplay extends HBox { public PersonDisplay(Person person) { // First, let's configure our root layout setSpacing(5); setAlignment(Pos.CENTER_LEFT); setPadding(new Insets(5)); // Add our profile picture ImageView imgProfilePic = new ImageView("/user.png"); imgProfilePic.setFitHeight(24); imgProfilePic.setFitWidth(24); getChildren().add(imgProfilePic); // A simple Separator between the photo and the details getChildren().add(new Separator(Orientation.VERTICAL)); // Now, create a VBox to hold the name and age VBox vBox = new VBox(5); vBox.setAlignment(Pos.CENTER_LEFT); vBox.setPadding(new Insets(5)); // Add our Person details vBox.getChildren().addAll( new Label("Name: " + person.getName()), new Label("Age: " + person.getAge()) ); // Add our VBox to the layout getChildren().add(vBox); } }
The Result:

ListViewfor this.