PlDataList
A list of labels and the values that go with them. The panel every detail screen ends with, and the whole reason it is a component is the markup: it says that "Owner" names "Ada Lovelace" rather than sitting beside it.
import { PlDataList, PlDataListItem } from 'plass-ui';
<PlDataList divider>
<PlDataListItem label="Owner" value="Ada Lovelace" />
<PlDataListItem label="Plan" value="Team" />
</PlDataList>;import 'package:plass_ui/plass_ui.dart';
PlDataList(
divider: true,
children: const <Widget>[
PlDataListItem(label: Text('Owner'), value: Text('Ada Lovelace')),
PlDataListItem(label: Text('Plan'), value: Text('Team')),
],
);Props
| Prop | Type | Default | Description |
|---|---|---|---|
| orientation | 'horizontal' | 'vertical' | 'horizontal' | Whether the label sits beside the value or above it |
| labelWidth | number | string | '10rem' | How wide the label column is. A fixed width rather than the longest label, so two panels on one screen line up |
| divider | boolean | false | Draws a hairline between the rows, and only between them |
| sizeshared | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' | The type scale of the labels and the values |
| densityshared | 'default' | 'compact' | 'default' | The space between the rows |
| children | ReactNode | — | The PlDataListItems |
| Prop | Type | Default | Description |
|---|---|---|---|
| children * | List<Widget> | — | The PlDataListItems |
| orientation | PlassOrientation | PlassOrientation.horizontal | Whether the label sits beside the value or above it |
| labelWidth | double? | 160 | How wide the label column is. A fixed width rather than the longest label, so two panels on one screen line up |
| divider | bool | false | Draws a hairline between the rows, and only between them |
| sizeshared | PlassSize | PlassSize.md | The type scale of the labels and the values |
| densityshared | PlassDensity | PlassDensity.standard | The space between the rows |
PlDataListItem
| Prop | Type | Default | Description |
|---|---|---|---|
| label | ReactNode | — | What the value is of |
| value | ReactNode | — | The value. Use children for a value with markup in it |
| icon | ReactNode | — | A glyph before the label |
| children | ReactNode | — | The value, when it is more than a string |
| Prop | Type | Default | Description |
|---|---|---|---|
| label | Widget? | — | What the value is of |
| value | Widget? | — | The value. Use children for a value with markup in it |
| icon | Widget? | — | A glyph before the label |
What the shared axes mean across the library is in prop conventions.
PlDataList, PlTable or PlList
Three components lay out rows of text, and they answer different questions.
PlDataList | One thing and its fields. A project's owner, plan, region, created date. |
PlTable | Many things with the same fields. |
PlList | A run of items of the same kind, with no fields at all. |
A details panel built as a two-column table is the common mistake, and it is not a styling one: a table claims a row-and-column relationship that is not there, so a reader navigating it by cell is told there are two columns of data when there is a column of names and a column of values.
That is what the markup is for. It is a real <dl> with real <dt>s and <dd>s, each pair grouped in a <div>, which the HTML specification allows, and which is what lets a row be laid out side by side without giving up the grouping that makes it a pair.
The Dart half of the same claim is MergeSemantics around each row: the label and its value are announced together. A label read on its own is a word, and a value read on its own is a fact nobody can place.
orientation
horizontal puts the label beside the value in a column of its own, which is the shape a details panel takes. vertical puts it above, for a narrow column, or for values long enough that a label beside them leaves the value nowhere to go.
The label column is a fixed width rather than the width of the longest label, and that is deliberate: two panels on one screen line up with each other, and a value does not move when somebody renames a field. labelWidth sets it.
'12ch' is usually the right value. A label column is measured in characters, and no ladder of rem can spell that.
Examples
Rows that need a rule between them
divider draws a hairline between the rows, and only between them. A line above the first or below the last would be a box drawn around a list that has no box.
<PlCard>
<PlDataList divider>…</PlDataList>
</PlCard>A value that is not a string
The value takes anything: a chip for a status, an avatar for a person, a link for a reference.
<PlDataListItem label="Status">
<PlChip color="success">Active</PlChip>
</PlDataListItem>value and children say the same thing. Use value for a string and children for markup.
PlDataListItem(label: const Text('Status'), value: const PlChip(child: Text('Active')));Notes
- The rows are children rather than data, unlike a
PlTable's columns. A details panel is written out once and read in source order, and every value in it is a different shape, so a data array would be an array ofrenderfunctions. - It draws no surface. A details panel sits in a
PlCard, and a sheet inside a sheet is two sheets. sizeanddensitycome from the list and reach every row, so a panel is one decision rather than one per line.
Accessibility
- The label and its value are announced as a pair. That is the component's whole reason to exist, and it is what a grid of
<div>s cannot do. - An
iconis decorative and is hidden from a screen reader: the label beside it already says what the field is. - A label is not a heading. Naming the panel is the page's job. A
<h2>above it, or anaria-labelon the region it sits in.