-
Notifications
You must be signed in to change notification settings - Fork 842
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for table footers #1202
Conversation
@snide @cchaos @ryankeairns @timroes et al, would appreciate any feedback you have on this! |
One other thought: I purposely kept the configuration minimal to be consistent with the table header implementation, but as a result there are two edge cases to consider:
We can definitely address these, it's just a question of importance and how we'd want to expose them. |
4108fc6
to
1889247
Compare
Per conversation with @chandlerprall, to keep things simple I will go ahead and always render a For now, if someone wants to set their own colspans or skip rendering a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall approach & design look great! Couple small changes.
or more of your columns contains a <EuiCode>footer</EuiCode> definition, | ||
the footer area will be visible. By default, columns with no footer specified | ||
(undefined) will render an empty cell to preserve the table layout. You | ||
can force <EuiCode>footer: null</EuiCode> if you want to override this |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
update description to remove null
specifics
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah totally missed this one. thanks for catching
footer: { | ||
description: `Content to display in the footer beneath this column`, | ||
required: false, | ||
type: { name: 'string | PropTypes.node | (items) => PropTypes.node' } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use PropTypes.element
instead of PropTypes.node
, it's a more restrictive and provides flexibility in the future. JS primitives (string, number, boolean, etc) or an array of primitives are acceptable node types. This would allow us to e.g. disable a column footer if false
is passed.
render: PropTypes.func, // ((value, record) => PropTypes.node (also see [services/value_renderer] for basic implementations) | ||
footer: PropTypes.oneOfType([ | ||
PropTypes.string, | ||
PropTypes.node, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PropTypes.element
here too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The functionality seems to work well. As mentioned below, I'll do a quick design PR against your fork for you.
I'm fine with making the assumption that all table footer cells should be <td>
's but I think the bigger argument would be for accessibility. I can't seem to find any true guidelines on this. We may end up needing to allow some configuration of this depending on what content they're putting in the footer, whether it's just a repeat of the column name or a summary of the column since both would need to have some level of aria support but in different ways.
* Indicates if the column should not show for mobile users | ||
* (typically hidden because a custom mobile header utilizes the column's contents) | ||
*/ | ||
hideForMobile: PropTypes.bool, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we'll ever support footers for mobile the way we are changing the layout for small screens. Go ahead and remove the props hideForMobile
and isMobileHeader
and any logic surrounding these.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, yes isMobileHeader
was there because we need to know not to include an empty <td>
for that column, however it would be cleaner to just filter this out of the column definition itself rather than relying on CSS to do the work for me. I'll update accordingly.
<td | ||
className={classes} | ||
colSpan={colSpan} | ||
scope={scope} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
scope
is not supported on <td>
elements
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, didn't realize this changed in HTML5. Thanks!
src/components/table/_table.scss
Outdated
@@ -113,6 +113,23 @@ | |||
@include euiTableCellCheckbox; | |||
} | |||
|
|||
// Must come after .euiTableRowCell selector for border to be removed | |||
.euiTableFooterCell, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This style works pretty well, though a lot of styles are redundant with the table header. I'll put up a PR against your fork for some cleanup.
src/components/table/_table.scss
Outdated
@@ -113,6 +113,23 @@ | |||
@include euiTableCellCheckbox; | |||
} | |||
|
|||
// Must come after .euiTableRowCell selector for border to be removed | |||
.euiTableFooterCell, | |||
.euiTableFooterRow .euiTableHeaderCellCheckbox { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the checkbox styles necessary? It seems that you don't pass the checkbox to the footer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no not necessary. totally meant to pull this out -- I was temporarily experimenting with checkboxes in the footer and didn't clean up the styles after i was done.
Could this be added a prop? |
@cchaos Yeah, in looking into it more, I'm realizing this would mostly just be useful with Perhaps we could pull e.g. footer: (items, pagination) => {
const { pageIndex, pageSize } = pagination;
const startIndex = pageIndex * pageSize;
const pageOfItems = items.slice(startIndex, Math.min(startIndex + pageSize, items.length));
// do something with pageOfItems
} Thoughts? |
I'm not super familiar with how passing functions works. @chandlerprall can you take a look at ^^? |
@cchaos @chandlerprall Just pushed some updates which I believe cover what we've discussed so far; please take a look whenever you have a sec. I'll wait to resolve the merge conflicts until we add the style updates from @cchaos. |
Looks like |
I also don't think those |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
small tweaks on that proptype (sorry!)
about including the pagination information to the footer callback function, let's pass both items and pagination in an object, e.g.
footer: ({items, pagination}) => {
const { pageIndex, pageSize } = pagination;
const startIndex = pageIndex * pageSize;
const pageOfItems = items.slice(startIndex, Math.min(startIndex + pageSize, items.length));
// do something with pageOfItems
}
this grants the flexibility to add more arguments in the future and letting the callback author pick & choose what values to grab, without caring about argument order.
Thanks, will remove those. (Didn't realize these were built during the release process) |
I like that idea -- will update. |
b6de9a3
to
416d3ce
Compare
@cchaos @chandlerprall Updates pushed; I think I covered everything on our hit list, but ping me with any other thoughts. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changes LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't want to hold up this PR, so feel free to merge.
My only comment after pulling it down is that we should likely show an example of the footer that is a common use case. I don't know that people will use it to replicate the table head very often, but more likely would use it to do summary or agg counts of the table contents? It'd be nice to present it that way... ex: 33 users online, 5 countries...etc.
Often people copy / paste our examples, so just giving some level of inspiration there can help. It wouldn't be the first time someone copied something from us and we wondered how something like "footers that duplicate the head" showed up in prod :)
Thanks for the changes. Looks good @lukeelmers |
Closes #493, which is a prerequisite for elastic/kibana#16639.
Summary
Introduces
<EuiTableFooter>
and<EuiTableFooterCell>
components to render a proper<tfoot>
in tables. Also adds support for footers to<EuiBasicTable>
via a newfooter
key in the column definition.Usage
Given the following column definition in
<EuiBasicTable>
, a<tfoot>
will automatically be added with the specified data:Notes, Caveats, & Discussion Points
footer
is specified in the column definition, the<tfoot>
will be rendered. By default, columns with no footer specified (undefined) will render an empty cell to preserve the table layout.You can force(removed; see comment below)footer: null
if you want to override this behavior on a per-column basis.colspan
is supported in the<EuiTableFooterCell>
component itself, but not within<EuiBasicTable>
.colspan
within<EuiBasicTable>
? Maybe, but we'll decide whether to add this in the future.column[i].footerColspan
is an option, but feels clumsy. We could also make a footer object (i.e.footer: { render, colspan, ...etc }
), but that may overcomplicate things for users. TBD later.footer
in the column definition, the whole list of available items is provided.Just want to note that this means the basic table implementation of footers has no knowledge of pagination... it just looks at all of the available items. This could be easily changed if we want it to, for example, only receive the current visible items.(addressed; see comment below)Checklist