Table Footer
- Stable
- WCAG 2.2 evidence
- RTL
The bar under a table: the range text, a rows-per-page select and the page controls. It is the
Figma composition of Select, range text and PageButtons; presentational, so you pass the page, the page size and the
range and it calls back (onPageChange, onPageSizeChange). The page controls are a named nav with a list of page
buttons or links (aria-current="page" on the current one, ellipses by siblingCount and boundaryCount); the controls
at the end of the list stay focusable with aria-disabled; a page change in place is announced politely (WCAG 1.3.1,
2.1.1, 2.4.1, 2.4.7, 4.1.2, 4.1.3). The compact layout keeps the range and previous and next for narrow cards. Name note: React Aria Components also exports a TableFooter (the tfoot section of its Table); this is the Nexera
footer bar that sits below the table, and it does not re-export the React Aria part. Consumer duties: a unique landmark name per table, the translated range, updating the rows when the page or
size changes.
import { TableFooter } from "@nexera-ui/react";- 6
- examples
- 17
- props
- 1
- live controls
- 1
- platform
- 8
- WCAG criteria
- 1
- block uses it
Try every prop. Copy the code.
Change the props and the code updates. Check light and dark, LTR and RTL, and phone width.
import { TableFooter } from "@nexera-ui/react";
<TableFooter />Examples 5
The same examples as Storybook, rendered live. Open Code to copy one.
Compact
Figma Layout=Compact: the range with previous and next icons, for narrow cards.
import { useState } from "react";
import { TableFooter } from "@nexera-ui/react";
const TOTAL = 128;
function Wired({
layout,
initialSize = 20,
label = "Employees",
}: {
layout?: "full" | "compact";
initialSize?: number;
label?: string;
}) {
const [page, setPage] = useState(1);
const [size, setSize] = useState(initialSize);
const pageCount = Math.ceil(TOTAL / size);
const current = Math.min(page, pageCount);
return (
<TableFooter
aria-label={label}
{...(layout === undefined ? {} : { layout })}
page={current}
pageCount={pageCount}
onPageChange={setPage}
pageSize={size}
onPageSizeChange={(next) => {
setSize(next);
setPage(1);
}}
range={`${String((current - 1) * size + 1)} to ${String(Math.min(current * size, TOTAL))} of ${String(TOTAL)}`}
/>
);
}
export function Compact() {
return <Wired layout="compact" label="Employees (compact)" />;
}
Page links
Links instead of buttons, for server-rendered or routed pages.
import { TableFooter } from "@nexera-ui/react";
<TableFooter
aria-label="Employees"
pageCount={7}
page={3}
getPageHref={(page: number) => `#page-${String(page)}`}
range="41 to 60 of 128"
/>;
Narrow width
Inside a 320 px column the row wraps: range, rows per page, then the page controls.
import { useState } from "react";
import { TableFooter } from "@nexera-ui/react";
const TOTAL = 128;
function Wired({
layout,
initialSize = 20,
label = "Employees",
}: {
layout?: "full" | "compact";
initialSize?: number;
label?: string;
}) {
const [page, setPage] = useState(1);
const [size, setSize] = useState(initialSize);
const pageCount = Math.ceil(TOTAL / size);
const current = Math.min(page, pageCount);
return (
<TableFooter
aria-label={label}
{...(layout === undefined ? {} : { layout })}
page={current}
pageCount={pageCount}
onPageChange={setPage}
pageSize={size}
onPageSizeChange={(next) => {
setSize(next);
setPage(1);
}}
range={`${String((current - 1) * size + 1)} to ${String(Math.min(current * size, TOTAL))} of ${String(TOTAL)}`}
/>
);
}
export function NarrowWidth() {
return (
<div className="max-w-xs">
<Wired label="Employees (narrow)" />
</div>
);
}
Long labels
Long translated strings wrap instead of truncating.
import { TableFooter } from "@nexera-ui/react";
export function LongLabels() {
return (
<div className="max-w-md">
<TableFooter
aria-label="Mitarbeiterverzeichnis"
page={2}
pageCount={7}
pageSize={20}
range="Einträge 21 bis 40 von insgesamt 128 Mitarbeitenden"
labels={{
rowsPerPage: "Zeilen pro Seite",
previous: "Vorherige Seite",
next: "Nächste Seite",
page: (page) => `Seite ${String(page)}`,
}}
/>
</div>
);
}
Right to left
Right to left: the range starts at the right and the previous and next glyphs mirror.
import { TableFooter } from "@nexera-ui/react";
export function RightToLeft() {
return (
<TableFooter
aria-label="الموظفون"
page={2}
pageCount={7}
pageSize={20}
range="٢١ إلى ٤٠ من ١٢٨"
labels={{
rowsPerPage: "الصفوف في الصفحة",
previous: "الصفحة السابقة",
next: "الصفحة التالية",
page: (page) => `صفحة ${String(page)}`,
}}
/>
);
}
Props 17
Press "Try it" on a card to load that prop into the playground.
17 props shown
layoutNexera"full" | "compact"Layout: full (range, rows per page, page numbers) or compact (range and previous and next icons).
rangeNexeraReactNodeText of the range. You compute and translate it so numbers and plural forms match your locale.
pageCount*NexeranumberNumber of pages.
pageNexeranumberCurrent page, from 1 (controlled). Use with onPageChange.
defaultPageNexeranumberPage on first render (uncontrolled).
onPageChangeNexera(page: number) => voidCalled with the new page when a control or page button is pressed.
pageSizeNexeranumberRows per page, controlled. Setting it, or defaultPageSize, shows the
rows-per-page select of the full layout. Reset the page in your handler when the size changes.
defaultPageSizeNexeranumberRows per page on first render (uncontrolled), which also shows the select.
onPageSizeChangeNexera(pageSize: number) => voidCalled with the size the user picked.
pageSizesNexerareadonly number[]The choices of the rows-per-page select. The current size is added when missing.
siblingCountNexeranumberPage numbers shown on each side of the current page (full).
boundaryCountNexeranumberPage numbers always shown at the start and at the end (full).
getPageHrefNexera(page: number) => stringMakes the page controls links: getPageHref(page) is each address. Without it they are buttons that change the page in place.
labelsNexeraPartial<PaginationLabels>Strings the footer invents (previous, next, page names, rows per page). Translate them.
getPageAnnouncementNexera(page: number, pageCount: number) => stringText announced politely after the page changed in place (not for page links).
aria-labelNexerastringAccessible name of the pagination landmark, for example "Employees". Say what is paged: a page with several nav
landmarks needs a unique name for each. Translate it.
Accessible name when it must differ from the visible text.
aria-labelledbyNexerastringId(s) of visible element(s) that name the landmark; wins over aria-label.
Id(s) of visible element(s) that name the landmark, for example the heading of the table.
* Required. React Aria props shown are the ones most apps use; the component accepts the rest of its React Aria props too.
Accessible by default.
Built on React Aria, and covered by the WCAG 2.2 evidence generated on every build.
WCAG 2.2 evidence
6 direct · 2 supporting- 1.3.1Info and RelationshipsLevel A · tested directly
- 1.4.10ReflowLevel AA · supporting test
- 1.4.12Text SpacingLevel AA · supporting test
- 2.1.1KeyboardLevel A · tested directly
- 2.4.1Bypass BlocksLevel A · tested directly
- 2.4.4Link Purpose (In Context)Level A · tested directly
- 4.1.2Name, Role, ValueLevel A · tested directly
- 4.1.3Status MessagesLevel AA · tested directly
Fits any width.
Nexera components respond to the space they are given. Drag the corner of the frame, or pick a width.
Styling hooks
Pass className to add Tailwind classes (merged last). State is exposed as data attributes, so you can style it with variants like data-pressed:.
<TableFooter className="shadow-sm" />Used in blocks
Related components
- BreadcrumbShows where the current page sits in the hierarchy and links back to each level.
- BreadcrumbItemOne level of a `Breadcrumb` trail; use it only inside `Breadcrumb`.
- CursorPagerA previous and next pair for data without stable page numbers, such as an activity log or a cursor API.
- FABThe main action of a mobile screen: a floating button with a `nav/active-bg` fill and a large shadow.
- FeedStatusThe status line at the bottom of an infinite feed or a lazy list: "Loading more", "You have reached the end" or "Could not load more" with a retry action.
- JumpToPageA small "Go to page [48] of 120" control for long paged lists.
- NavigationBarThe bottom bar of a mobile layout: a named `nav` landmark with a list of three to five `NavItem`s.
- NavItemOne destination or action of a `NavigationBar`.