Styling guide
The fields generated by eidos are structured with a single div
wrapper, and then all fields being direct children of that div
.
The core principle behind this, is that one can use CSS to layout and style the field to match any usecase it may serve.
This means that you only have to write and maintain some CSS code for each field and not the actual contents.
Below we give an outline of the most common styles to apply to a field.
Table layouts
Out of the box the layout of the table might not be exactly what you want it to be. Luckily, the layout is easy to adjust. Our recommended way of overriding table styles is to give your page a wrapping element with some unique class name, then use this to increase the specificity of your CSS rules. For instance:
function MyPage() {
return (
<Page className="MyPage">
<EditableTable {...props} />
</Page>
);
}
Then in a CSS file, (name it MyPage.css
, it is handy to keep filenames aligned like this) put styles such as
/* Adjust margin of all table cells */
.MyPage .TableRow > * > * {
margin: 8px;
}
And do not forget to import this CSS file in your JS file!
Adjusting columns
Since the table uses a flex layout by default, each column gets the same width (and the row actions have a fixed with, more on this later). So, every time you create a new table, you will need to create a new stylesheet to adjust the column widths. Doing so is fairly straightforward, since each column gets its own class name derived from the key it is displaying.
For instance, if we are creating a table for the type Item
given by
interface Item extends BaseObject {
name: string;
description: text;
price: number;
}
The values of the properties name
and description
will obviously take up more space than the price
property. So, we may add the following CSS rule:
.ItemPage .name,
.ItemPage .description {
flex: 3;
}
(Assuming our table is wrapped by some element with class name "ItemPage"
).
This way, the table's width will be divided over the columns to a ratio of 3:3:1.
Then, to adjust the width actions column, we recommend using a fixed width. By default, this is 210px
, in order to have space for three icon buttons.
In which we measure 70px
for each icon button. So if we know that our table only has two actions in each row, we may add the rule:
.ItemPage .RowActions,
.ItemPage .HeaderActions {
flex: 0 0 140px;
}
It is also possible to change the order of the columns by using the CSS order
property. This way you can change the order of the columns without having to edit your eidos.ts
file. It is also the case that inherited properties, like the id
or the listIndex
in the case of an object that extends OrderedListMember
, are automatically appended at the end of your type, and thus these columns will be rendered last. The listIndex
is likely desired to be the first column. To fix this, add the following CSS rule:
/* listIndex property */
.MyPage .OrderedTable .listIndex {
order: -1;
}
/* Handle for drag reordering */
.MyPage .OrderedTable div[draggable] {
order: -2;
}
Note
The above CSS rule for reordering the
listIndex
property may become a default in future eidos versions.
Grid-based row layouts
The table layouts are not limited to just display: flex
.
If a simple tablerow is not what you are after, you can give your display component a display: grid
,
and then lay out your properties according to a grid layout.
In the following snippet, we transform our Item
rows into a grid layout, place the name
and price
on the first grid-row
,
and then put the description on its own two grid-row
s:
.ItemPage .Item {
padding: 16px;
display: grid;
grid-template-columns: 2fr 1fr;
grid-template-rows: auto;
gap: 8px;
}
.ItemPage .name {
grid-column: 1 / 3;
}
.ItemPage .price {
grid-column: 3 / 3;
}
.ItemPage .description {
grid-column: 1 / 4;
grid-row: 2 / 4;
}
Editing state
If you are using inline editing, and want to change the layout of your row based on whether editing is currently enabled or disabled, you can do so as follows:
import { Page, EditableTable, useEditing, useSave, endpoints } from "@bronscode/eidos";
import { Button } from "@mui/material";
function MyPage() {
const [items, setItem, putItem, deleteItem] = useSave(endpoints.items);
const [editable, setEditable] = useEditing();
return (
<Page className="Items">
<Button onClick={() => setEditing(!editable)}>Toggle editing</Button>
<EditableTable
title="Items"
className={editable ? "editable" : ""}
values={items}
setObject={setItem}
addObject={putItem}
deleteObject={deleteItem}
editable={editable}
inline
/>
</Page>
);
}
Then, in your CSS, we can for instance change the width of the first column based on whether the table is being edited or not
.ItemPage .name {
flex: 2;
}
.ItemPage .EditableTable.editable .name {
flex: 3;
}
Dialog view
If you are not using inline editing, so that editing occurs in a dialog, you may also want to change the style properties of certain items depending on whether they are being displayed in a table row or in the edit dialog. The edit dialog has the class name "EditDialog"
. For instance, if we want a certain field to have a larger height in the table view, this is accomplished by the following rule:
.ItemPage .EditDialog .description {
height: 400px;
}
Row states
Suppose we want to style a row differently depending on some property of the row value.
We continue with the previous example, but we add a inStock
property to the Item
type:
interface Item extends BaseObject {
name: string;
description: text;
price: number;
inStock: number;
}
If the item is not in stock, we want to grey out the entire row. We do so as follows:
import { ItemField } from "../fields/fields.js";
const ItemDisplay = ({ value, onChange, editable }) => {
return (
<ItemField
value={value}
onChange={onChange}
editable={editable}
className={value.inStock > 0 ? "" : "out-of-stock"}
/>
);
};
Now, when we create our DisplayTable
with this ItemDisplay
as our DisplayComponent
, we can address the .out-of-stock
class in our stylesheet:
.ItemPage .Item.out-of-stock > * {
opacity: 0.5;
}