npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@financial-times/o-table

v9.3.5

Published

Provides styling and behvaiour for tables across FT products.

Downloads

4,500

Readme

o-table

Styling for tables.

Usage

Check out how to include Origami components in your project to get started with o-table.

Markup

Basic table

Add an o-table class to any table you wish to apply the styles to:

<table class="o-table" data-o-component="o-table">
	...
</table>

Where table headings (th) are used as row headings, scope="row" attributes must be set on the th:

<table class="o-table" data-o-component="o-table">
	<tbody>
		<tr>
			<th scope="row" role="rowheader">Item</th>
			<td>Holiday</td>
			<td>Lunch</td>
		</tr>
		<tr>
			<th scope="row" role="rowheader">Cost</th>
			<td>£123.45</td>
			<td>£7</td>
		</tr>
	</tbody>
	...
</table>

The table's caption element should include a header of the appropriate level and style for the table's context.

<table class="o-table" data-o-component="o-table">
	<caption class="o-table__caption">
		<h2>My Table Caption</h2>
	</caption>
	<thead>
		...
	</thead>
	<tbody>
		...
	</tbody>
	...
</table>

The table's footer tfoot element may use the helper class o-table-footnote to display sources, disclaimers, etc.

<table class="o-table" data-o-component="o-table">
	<thead>
		...
	</thead>
	<tbody>
		...
	</tbody>
	<tfoot>
		<tr>
			<td colspan="2" class="o-table-footnote">Source: The Origami team.</td>
		</tr>
	</tfoot>
</table>

Sort Order

When a sortable table column is clicked an ascending sort is applied by default. If clicked again the sort order is toggled to a descending sort. Set the preferred sort order attribute data-o-table-preferred-sort-order="descending" to inverse this, so a descending sort is applied on the first click.

<table
	class="o-table"
	data-o-component="o-table"
	data-o-table-preferred-sort-order="descending"
></table>

Disable sort

Table columns are sortable by default but may be disabled by adding data-o-table-sortable="false" to the table.

<table
	class="o-table"
	data-o-component="o-table"
	data-o-table-sortable="false"
></table>

Or to disable sort per table column, add data-o-table-heading-disable-sort to the column's th element.

<table class="o-table" data-o-component="o-table">
	<thead>
		<tr>
			<th>Heading One</th>
			<!-- do not show the actions column as sortable -->
			<th data-o-table-heading-disable-sort>Actions</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>Item One</td>
			<td><a href="#edit">edit</a></td>
		</tr>
	</tbody>
</table>

Responsive options

There are three options for small viewports where the table does not fit.

  1. overflow - Scroll the whole table including headings horizontally. This option also supports an expander.
  2. scroll - Flip the table so headings are in the first column and sticky, data is scrollable horizontally.
  3. flat - Split each row into an individual item and repeat headings.

To enable these set data-o-table-responsive to the type of responsive table desired and add the classes for that type of table. Then wrap the table in o-table-container, o-table-overlay-wrapper, o-table-scroll-wrapper. E.g for an "overflow" table:

<div class="o-table-container">
	<div class="o-table-overlay-wrapper">
		<div class="o-table-scroll-wrapper">
			<table
				class="o-table o-table--horizontal-lines o-table--responsive-overflow"
				data-o-component="o-table"
				data-o-table-responsive="overflow"
			>
				...
			</table>
		</div>
	</div>
</div>

If your project does not use the build service, you may need to specify an extra Sass option for responsive features and initialise o-table JavaScript. More examples are available in the registry.

Expander

The "overflow" style of responsive table (see above) supports an expander to hide rows and offer a "show more" / "show fewer" button. To enable this feature set data-o-table-expanded="false" to the table. The number of rows to show when the table is not expanded can be configured with data-o-table-minimum-row-count="20" (default: 20).

<div class="o-table-container">
	<div class="o-table-overlay-wrapper">
		<div class="o-table-scroll--wrapper">
			<table
				class="o-table o-table--horizontal-lines o-table--responsive-overflow"
				data-o-component="o-table"
				data-o-table-responsive="overflow"
				data-o-table-expanded="false"
				data-o-table-minimum-row-count="10"
			>
				...
			</table>
		</div>
	</div>
</div>

To add a footnote to an expandable table, for example with disclaimers or sources, add the footnote within the container and link to the table with an id and the aria-describedby attribute. If not working on an expandable table, use the tfoot element instead.

<div class="o-table-container">
	<div class="o-table-overlay-wrapper">
		<div class="o-table-scroll--wrapper">
+			<table aria-describedby="demo-footnote">
				...
			</table>
		</div>
	</div>
+	<div id="demo-footnode" class="o-table-footnote">
+		Source: The Origami team's love of fruit.
+	</div>
</div>

Additional markup

  • o-table--compact - Apply to the table for smaller typography and padding.
  • o-table--row-stripes - Apply to the table for alternating stripes on the table rows.
  • o-table-footnote - Style a tfoot element subtily for sources, disclaimers, etc.
  • o-table__cell--numeric - Apply to numeric cells to align content to the right.
  • o-table__cell--vertically-center - Apply to cells which should center vertically.

See more in the registry: o-table demos.

Sass

Use @include oTable() to include styles for all table features. Alternatively styles may be included granularly with an $opts map.

Include all table features:

@include oTable();

Alternatively include base styles with only selected optional features. E.g. to include only the "overflow" responsive table and styles for table lines:

@include oTable(
	$opts: (
		'responsive-overflow',
		'lines',
	)
);

| Feature | Description | Brand support | | ------------------- | ------------------------------------------------------- | -------------------------- | | responsive-overflow | See responsive options. | core, internal, whitelabel | | responsive-flat | See responsive options. | core, internal, whitelabel | | responsive-scroll | See responsive options. | core, internal, whitelabel | | lines | Styles for horizontal and vertical lines, plus borders. | core, internal, whitelabel | | compact | A table with smaller typography and padding. | core, internal, whitelabel | | stripes | Alternating row stripe styles. | core, internal | | row-headings | Row heading styles. | internal |

JavaScript

To manually instantiate o-table:

import OTable from '@financial-times/o-table';
OTable.init();

or

import OTable from '@financial-times/o-table';
oTable = new OTable(document.body);

This will return an instance of BasicTable (default), OverflowTable, FlatTable, or ScrollTable depending on the value of data-o-table-responsive. All four table types extend BaseTable.

Instantiation will add column sorting to all tables. It will also add scroll controls and, if configured, an expander to any OverflowTable. These can be configured with data attributes or imperatively with an options object:

import OTable from '@financial-times/o-table';
OTable.init(document.body, {
	sortable: true,
	expanded: true,
	preferredSortOrder: 'ascending',
	minimumRowCount: 10,
});

Filtering

All o-table instances support filtering on a single column. Filters may be applied declaratively in HTML or by calling the o-table JavaScript method filter.

The style of form elements used to filter a table are not determined by o-table. However we recommend using o-forms to style form elements used to filter an o-table, such as input or select elements. See the o-table filter demos in the component registry for a demo using o-forms styles.

Filter (declarative)

Declarative filters are case insensitive and perform partial matches, e.g. a filter of "Kingdom" would reveal "United Kingdom".

To enable declarative table filtering add the data-o-table-filter-id and data-o-table-filter-column to a form input. Where data-o-table-filter-id matches the id of the table to filter and data-o-table-filter-column is the numerical index of the column to filter (starting at 0).

For example, to filter a table based on a users selected option:

<label>Filter the table by country:</label>
<!-- the filter input specifies the table id in "data-o-table-filter-id" -->
<select data-o-table-filter-id="example-table" data-o-table-filter-column="0">
	<option value="" selected>All</option>
	<option value="​Austria">​Austria</option>
	<option value="​Belgium">​Belgium</option>
	<!-- more options  -->
</select>

<!-- the table markup, this may be a responsive table -->
<div class="o-table-container">
	<!-- the table element with an id -->
	<table id="example-table">
		<!-- ... -->
	</table>
</div>

Or to filter a table based on a users selected option:

<label>Filter the table by country:</label>
<!-- the filter input specifies the table id in "data-o-table-filter-id" -->
<input
	type="text"
	data-o-table-filter-id="example-table"
	data-o-table-filter-column="0"
/>

<!-- the table markup, this may be a responsive table -->
<div class="o-table-container">
	<!-- the table element with an id -->
	<table id="example-table">
		<!-- ... -->
	</table>
</div>

Filter (imperative)

The table's filter method may also be used to filter the table. Call it with the column index to filter and the filter to apply. The filter may be a string, which acts like a declarative filter (i.e. is case insensitive and performs a partial match):

const table = new OTable(tableElement);
table.filter(0, 'United Kingdom'); // Filter the first table column by "United Kingdom".

Alternatively a callback function may be given. The callback should accept a table cell element and return a boolean value:

const table = new OTable(tableElement);
table.filter(0, cell => {
	return parseInt(cell.textContent, 10) > 3;
}); // Filter the first table column. Keep rows with a value more than 3.

Sorting

All o-table instances support sorting. Sorting on non-string values such as numbers works if the column type has been declared. E.g. for a column of numbers add the following to o-table: data-o-table-data-type="number".

Other data types for data-o-table-data-type include:

| type | description | examples | | -------- | --------------------------------------------------------------------------------------------- | ------------------------------------------ | | text | The default, content is sorted as a string. | "Jane Doe", "John Smith" | | date | Supports the FT style of date and time, including abbreviation. | "Aug 17", "1.30am", "April 20 2014 1.30pm" | | number | Any number which may include number formatting and abbreviation. | "1,200", "100", "3.2", "1bn", "2tn" | | percent | Any percentage with or without the symbol "%". | "3.3%", "200%", "50%" | | currency | Any currency, which may include number formatting, number abbreviation, and currency symbols. | "$84m", "£36bn", "HK$90bn", "Rp14.595" | | numeric | A column which may be treated as numeric which does not fit a more specific type. | "101 dalmatians" |

It is possible to add sort support for a custom data type. Alternatively, the behaviour of an existing type may be modified.

Custom sort (declarative)

If you are wanting to sort by a custom pattern, you can apply the sorting values to each row as a data attribute: data-o-table-sort-value=${sort-value}. These values can be strings or integers.

For example to support a custom date format set data-o-table-sort-value to its UNIX Epoch.

<table class="o-table" data-o-component="o-table">
	<thead>
		<tr>
			<th data-o-table-data-type="date">Custom Date Formats</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td data-o-table-sort-value="1533081600">Wednesday, 1 August 2018</td>
		</tr>
		<tr>
			<td data-o-table-sort-value="1483228800">Jan 2017</td>
		</tr>
		<tr>
			<td data-o-table-sort-value="723168000">1st December 1992</td>
		</tr>
	</tbody>
</table>

Or to provide an arbitrary sort order:

<table class="o-table" data-o-component="o-table">
	<thead>
		<tr>
			<th>Things</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td data-o-table-sort-value="2">snowman</td>
		</tr>
		<tr>
			<td data-o-table-sort-value="3">42</td>
		</tr>
		<tr>
			<td data-o-table-sort-value="1">pangea</td>
		</tr>
	</tbody>
</table>

Custom sort (imperative)

Rather than specify data-o-table-sort-value declaratively, a formatter function may be provided client-side to generate sort values for a given data type.

For example we could add support for a custom data type emoji-time.

<table class="o-table" data-o-component="o-table">
	<thead>
		<tr>
			<th data-o-table-data-type="emoji-time">Emoji Time</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>🌑</td>
		</tr>
		<tr>
			<td>🌤️️</td>
		</tr>
		<tr>
			<td>🌑</td>
		</tr>
		<tr>
			<td>🌤️️</td>
		</tr>
	</tbody>
</table>

To do that call setSortFormatterForType with the custom data type and a formatter function. The formatter accepts the table cell (HTMLElement) and returns a sort value (Number or String) for that cell. In this case we add support for our custom type emoji-time by assigning the emoji a numerical sort value. This will effect all tables instantiated by OTable.

import OTable from '@financial-times/o-table';
// Set a filter for custom data type "emoji-time".
// The return value may be a string or number.
OTable.setSortFormatterForType('emoji-time', cell => {
	const text = cell.textContent.trim();
	if (text === '🌑') {
		return 1;
	}
	if (text === '🌤️️') {
		return 2;
	}
	return 0;
});
OTable.init();

Which for an ascending sort, will result in:

<table class="o-table" data-o-component="o-table">
	<thead>
		<tr>
			<th data-o-table-data-type="emoji-time" aria-sort="ascending">
				Emoji Time
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td data-o-table-sort-value="1">🌑</td>
		</tr>
		<tr>
			<td data-o-table-sort-value="1">🌑</td>
		</tr>
		<tr>
			<td data-o-table-sort-value="2">🌤️️</td>
		</tr>
		<tr>
			<td data-o-table-sort-value="2">🌤️️</td>
		</tr>
	</tbody>
</table>

Dynamic Rows

If rows are added or removed dynamically after the table is initialised call updateRows; this will apply any existing sort or filter to the new rows.

Events

The following events are fired by o-table.

  • oTable.ready
  • oTable.sorting
  • oTable.sorted

oTable.ready

oTable.ready fires when the table has been initialised.

The event provides the following properties:

  • detail.instance - The initialised o-table instance (FlatTable | ScrollTable | OverflowTable | BasicTable).

oTable.sorted

oTable.sorted indicates a table has finished sorting. It includes details of the current sort status of the table.

The event provides the following properties:

  • detail.sortOrder - The sort order e.g. "ascending" (String).
  • detail.columnIndex - The index of the sorted column heading (Number).
  • detail.instance - The effected o-table instance (FlatTable | ScrollTable | OverflowTable | BasicTable).
document.addEventListener('oTable.sorted', event => {
	console.log(
		`The target table was just sorted by column "${event.detail.columnIndex}" in an "${event.detail.sortOrder}" order.`
	);
});

oTable.sorting

This event is fired just before a table sorts based on user interaction. It may be prevented to implement custom sort functionality. This may be useful to sort a paginated table server-side.

The event provides the following properties:

  • detail.sort - The sort requested e.g. "ascending" (String).
  • detail.columnIndex - The index of the column heading which will be sorted (Number).
  • detail.instance - The effected o-table instance (FlatTable | ScrollTable | OverflowTable | BasicTable).

When intercepting the default sort the sorted method must be called with relevant parameters when the custom sort is completed.

document.addEventListener('oTable.sorting', event => {
	// Prevent default sorting.
	event.preventDefault();
	// Update the table with a custom sort.
	console.log(`Update the table with sorted data here.`);
	// Fire the sorted event, passing along the column index and sort.
	event.detail.instance.sorted({
		columnIndex: event.detail.columnIndex,
		sortOrder: event.detail.sort,
	});
});

Get The Sorted Column Heading From A Sort Event

o-table sort events provide a columnIndex. This index maps to a column heading. To retrieve the column heading use getTableHeader.

document.addEventListener('oTable.sorting', event => {
	const table = event.detail.instance;
	const columnIndex = event.detail.columnIndex;
	// Get the table header from the column index.
	console.log(table.getTableHeader(columnIndex));
});

Migration

| State | Major Version | Last Minor Release | Migration guide | | :----------: | :-----------: | :----------------: | :---------------------------------------------------: | | ✨ active | 9 | N/A | migrate to v9 | | ✨ active | 8 | 8.1 | migrate to v8 | | ⚠ maintained | 7 | 7.4 | migrate to v7 | | ╳ deprecated | 6 | 6.9 | migrate to v6 | | ╳ deprecated | 5 | 5.2 | migrate to v5 | | ╳ deprecated | 4 | 4.1 | migrate to v4 | | ╳ deprecated | 3 | 3.0 | N/A | | ╳ deprecated | 2 | 2.0 | N/A | | ╳ deprecated | 1 | 1.7 | N/A |

Contact

If you have any questions or comments about this component, or need help using it, please either raise an issue, visit #origami-support or email Origami Support.

Licence

This software is published by the Financial Times under the MIT licence.