diff --git a/ccm-core/src/main/java/org/libreccm/pagemodel/layout/FlexBox.java b/ccm-core/src/main/java/org/libreccm/pagemodel/layout/FlexBox.java
new file mode 100644
index 000000000..de0c17205
--- /dev/null
+++ b/ccm-core/src/main/java/org/libreccm/pagemodel/layout/FlexBox.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2018 LibreCCM Foundation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+package org.libreccm.pagemodel.layout;
+
+import org.libreccm.core.CoreConstants;
+import org.libreccm.pagemodel.ComponentModel;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+
+/**
+ * A box in a {@link FlexLayout}.
+ *
+ * @author Jens Pelzetter
+ */
+@Entity
+@Table(name = "FLEX_LAYOUT_BOXES", schema = CoreConstants.DB_SCHEMA)
+@NamedQueries(
+@NamedQuery(name = "FlexBox.findBoxesForLayout",
+ query = "SELECT b FROM FlexBox b WHERE b.layout = :layout"))
+public class FlexBox implements Serializable {
+
+ private static final long serialVersionUID = -6085798536072937899L;
+
+ @Id
+ @Column(name = "BOX_ID")
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private long boxId;
+
+ @ManyToOne
+ private FlexLayout layout;
+
+ @Column(name = "BOX_ORDER")
+ private int order;
+
+ @Column(name = "BOX_SIZE")
+ private int size;
+
+ @OneToOne
+ @JoinColumn(name = "COMPONENT_ID")
+ private ComponentModel component;
+
+ public long getBoxId() {
+ return boxId;
+ }
+
+ public void setBoxId(final long boxId) {
+ this.boxId = boxId;
+ }
+
+ public FlexLayout getLayout() {
+ return layout;
+ }
+
+ protected void setLayout(final FlexLayout layout) {
+ this.layout = layout;
+ }
+
+ public int getOrder() {
+ return order;
+ }
+
+ public void setOrder(final int order) {
+ this.order = order;
+ }
+
+ public int getSize() {
+ return size;
+ }
+
+ public void setSize(final int size) {
+ this.size = size;
+ }
+
+ public ComponentModel getComponent() {
+ return component;
+ }
+
+ public void setComponent(final ComponentModel component) {
+ this.component = component;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 5;
+ hash = 89 * hash + (int) (boxId ^ (boxId >>> 32));
+ hash = 89 * hash + order;
+ hash = 89 * hash + size;
+ hash = 89 * hash + Objects.hashCode(component);
+ return hash;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof FlexBox)) {
+ return false;
+ }
+ final FlexBox other = (FlexBox) obj;
+ if (!other.canEqual(this)) {
+ return false;
+ }
+ if (boxId != other.getBoxId()) {
+ return false;
+ }
+ if (order != other.getOrder()) {
+ return false;
+ }
+ if (size != other.getSize()) {
+ return false;
+ }
+ return Objects.equals(component, other.getComponent());
+ }
+
+ public boolean canEqual(final Object obj) {
+ return obj instanceof FlexBox;
+ }
+
+ @Override
+ public final String toString() {
+ return toString("");
+ }
+
+ public String toString(final String data) {
+ return String.format("%s{ "
+ + "columnId = %d, "
+ + "order = %d"
+ + "size = %d, "
+ + "component = %s%s"
+ + " }",
+ super.toString(),
+ boxId,
+ order,
+ size,
+ Objects.toString(component),
+ data);
+ }
+
+}
diff --git a/ccm-core/src/main/java/org/libreccm/pagemodel/layout/FlexBoxRepository.java b/ccm-core/src/main/java/org/libreccm/pagemodel/layout/FlexBoxRepository.java
new file mode 100644
index 000000000..f417572b4
--- /dev/null
+++ b/ccm-core/src/main/java/org/libreccm/pagemodel/layout/FlexBoxRepository.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 LibreCCM Foundation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+package org.libreccm.pagemodel.layout;
+
+import org.libreccm.core.AbstractEntityRepository;
+
+import java.util.List;
+
+import javax.enterprise.context.RequestScoped;
+import javax.persistence.TypedQuery;
+import javax.transaction.Transactional;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+@RequestScoped
+public class FlexBoxRepository extends AbstractEntityRepository {
+
+ private static final long serialVersionUID = -5321887349687319620L;
+
+ @Override
+ public Class getEntityClass() {
+ return FlexBox.class;
+ }
+
+ @Override
+ public String getIdAttributeName() {
+ return "boxId";
+ }
+
+ @Override
+ public Long getIdOfEntity(final FlexBox entity) {
+ return entity.getBoxId();
+ }
+
+ @Override
+ public boolean isNew(final FlexBox entity) {
+ return entity.getBoxId() == 0;
+ }
+
+ @Transactional(Transactional.TxType.REQUIRED)
+ public List getBoxesForLayout(final FlexLayout layout) {
+
+ final TypedQuery query = getEntityManager()
+ .createNamedQuery("FlexBox.findBoxesForLayout", FlexBox.class);
+ query.setParameter("layout", layout);
+
+ return query.getResultList();
+ }
+}
diff --git a/ccm-core/src/main/java/org/libreccm/pagemodel/layout/FlexDirection.java b/ccm-core/src/main/java/org/libreccm/pagemodel/layout/FlexDirection.java
new file mode 100644
index 000000000..fc972b347
--- /dev/null
+++ b/ccm-core/src/main/java/org/libreccm/pagemodel/layout/FlexDirection.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 LibreCCM Foundation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+package org.libreccm.pagemodel.layout;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+public enum FlexDirection {
+
+ HORIZONTAL,
+ VERTICAL
+
+}
diff --git a/ccm-core/src/main/java/org/libreccm/pagemodel/layout/FlexLayout.java b/ccm-core/src/main/java/org/libreccm/pagemodel/layout/FlexLayout.java
new file mode 100644
index 000000000..5eecb3e56
--- /dev/null
+++ b/ccm-core/src/main/java/org/libreccm/pagemodel/layout/FlexLayout.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2018 LibreCCM Foundation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+package org.libreccm.pagemodel.layout;
+
+import org.libreccm.core.CoreConstants;
+import org.libreccm.pagemodel.ComponentModel;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToMany;
+import javax.persistence.OrderBy;
+import javax.persistence.Table;
+
+/**
+ * A layout component container which provides the information for laying
+ * out other components using the Flex Layout properties in CSS.
+ *
+ * The component contains a collection of {@code FlexBox} objects which contain
+ * another component. A theme should use the Flex Layout properties in CSS to
+ * create the real layout.
+ *
+ * @author Jens Pelzetter
+ */
+@Entity
+@Table(name = "HORIZONTAL_LAYOUT_COMPONENTS", schema = CoreConstants.DB_SCHEMA)
+public class FlexLayout extends ComponentModel {
+
+ private static final long serialVersionUID = 1977244351125227610L;
+
+ /**
+ * The direction in which the components are shown. This is really only a
+ * hint for the theme, usually for the layout on wide screens. On small
+ * screens is is most likely that the boxes are stacked vertically.
+ */
+ @Column(name = "DIRECTION")
+ @Enumerated(EnumType.STRING)
+ private FlexDirection direction;
+
+ /**
+ * The boxes containing the components.
+ */
+ @OneToMany(mappedBy = "layout")
+ @OrderBy(value = "order")
+ @JoinColumn(name = "LAYOUT_ID")
+ private List boxes;
+
+ public FlexLayout() {
+ boxes = new ArrayList<>();
+ }
+
+ public FlexDirection getDirection() {
+ return direction;
+ }
+
+ public void setDirection(final FlexDirection direction) {
+ this.direction = direction;
+ }
+
+ public List getBoxes() {
+ return Collections.unmodifiableList(boxes);
+ }
+
+ protected void setBoxes(final List boxes) {
+ this.boxes = new ArrayList<>(boxes);
+ }
+
+ protected void addBox(final FlexBox box) {
+ boxes.add(box);
+ }
+
+ protected void removeBox(final FlexBox box) {
+ boxes.remove(box);
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 3;
+ hash = 67 * hash + Objects.hashCode(direction);
+ hash = 67 * hash + Objects.hashCode(boxes);
+ return hash;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof FlexLayout)) {
+ return false;
+ }
+ final FlexLayout other = (FlexLayout) obj;
+ if (!other.canEqual(this)) {
+ return false;
+ }
+ if (direction != other.getDirection()) {
+ return false;
+ }
+ return Objects.equals(boxes, other.getBoxes());
+ }
+
+ @Override
+ public boolean canEqual(final Object obj) {
+ return obj instanceof FlexLayout;
+ }
+
+ @Override
+ public String toString(final String data) {
+ return super.toString(String.format(", "
+ + "direction = %s, "
+ + "layoutCells = %s",
+ direction,
+ Objects.toString(boxes)));
+ }
+
+}
diff --git a/ccm-core/src/main/java/org/libreccm/pagemodel/layout/FlexLayoutManager.java b/ccm-core/src/main/java/org/libreccm/pagemodel/layout/FlexLayoutManager.java
new file mode 100644
index 000000000..e51857c9f
--- /dev/null
+++ b/ccm-core/src/main/java/org/libreccm/pagemodel/layout/FlexLayoutManager.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2018 LibreCCM Foundation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+package org.libreccm.pagemodel.layout;
+
+import org.libreccm.pagemodel.ComponentModelRepository;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+import javax.enterprise.context.RequestScoped;
+import javax.inject.Inject;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+@RequestScoped
+public class FlexLayoutManager implements Serializable {
+
+ private static final long serialVersionUID = 6697380241367469301L;
+
+ @Inject
+ private ComponentModelRepository componentModelRepo;
+
+ @Inject
+ private FlexBoxRepository flexBoxRepo;
+
+ public void addBoxToLayout(final FlexBox box, final FlexLayout layout) {
+
+ Objects.requireNonNull(box);
+ Objects.requireNonNull(layout);
+
+ layout.addBox(box);
+ box.setLayout(layout);
+
+ componentModelRepo.save(layout);
+ flexBoxRepo.save(box);
+ }
+
+ public void removeBoxFromLayout(final FlexBox box,
+ final FlexLayout layout) {
+
+ Objects.requireNonNull(box);
+ Objects.requireNonNull(layout);
+
+ layout.removeBox(box);
+ box.setLayout(null);
+
+ componentModelRepo.save(layout);
+ flexBoxRepo.delete(box);
+ }
+
+ public void decreaseBoxOrder(final FlexLayout layout,
+ final FlexBox box) {
+
+ Objects.requireNonNull(box);
+ Objects.requireNonNull(layout);
+
+ final int currentPosition = layout.getBoxes().indexOf(box);
+
+ if (currentPosition < 0) {
+ throw new IllegalArgumentException(String
+ .format("The FlexBox with ID %d is not part "
+ + "of the FlexLayout \"%s\".",
+ box.getBoxId(),
+ layout.getUuid()));
+ }
+
+ final FlexBox prevBox;
+ if ((currentPosition - 1) > 0) {
+ prevBox = layout.getBoxes().get(currentPosition -1);
+ } else {
+ // No previous box, return silently.
+ return;
+ }
+
+ final int prevPosition = prevBox.getOrder();
+
+ prevBox.setOrder(currentPosition);
+ box.setOrder(prevPosition);
+
+ flexBoxRepo.save(box);
+ flexBoxRepo.save(prevBox);
+ }
+
+ public void increaseBoxOrder(final FlexLayout layout,
+ final FlexBox box) {
+
+ Objects.requireNonNull(box);
+ Objects.requireNonNull(layout);
+
+ final int currentPosition = layout.getBoxes().indexOf(box);
+
+ if (currentPosition < 0) {
+ throw new IllegalArgumentException(String
+ .format("The FlexBox with ID %d is not part "
+ + "of the FlexLayout \"%s\".",
+ box.getBoxId(),
+ layout.getUuid()));
+ }
+
+ final FlexBox nextBox;
+ if ((currentPosition + 1) < layout.getBoxes().size()) {
+ nextBox = layout.getBoxes().get(currentPosition + 1);
+ } else {
+ // No previous box, return silently.
+ return;
+ }
+
+ final int nextPosition = nextBox.getOrder();
+
+ nextBox.setOrder(currentPosition);
+ box.setOrder(nextPosition);
+
+ flexBoxRepo.save(box);
+ flexBoxRepo.save(nextBox);
+
+ }
+
+}