diff --git a/docs/assets/android-tutorial-desktop.png b/docs/assets/android-tutorial-desktop.png
new file mode 100644
index 000000000..10c162e5f
Binary files /dev/null and b/docs/assets/android-tutorial-desktop.png differ
diff --git a/docs/tutorial/js-table.md b/docs/tutorial/js-table.md
new file mode 100644
index 000000000..c97bb9f29
--- /dev/null
+++ b/docs/tutorial/js-table.md
@@ -0,0 +1,204 @@
+---
+id: js-table
+title: Showing a table
+---
+
+Now that we have the native side covered, let's display the data we're sending
+on the desktop side.
+
+
+
+## Dynamic Plugin loading
+
+By default, Flipper will start with the plugins it was bundled with. You can
+configure it to also look for plugins in custom directories. To do that,
+modify the `~/.flipper/config.json` file that is created the first time
+you start Flipper and add a newly created directory the `pluginPaths` attribute.
+
+Your file will then look something like this:
+
+```json
+{
+ "pluginPaths": [
+ "~/.flipper/custom-plugins/"
+ ],
+ ...
+}
+```
+
+## Creating the Plugin Package
+
+With the loading part out of the way, we can create the new plugin. For that, first
+create a new folder inside the custom plugins directory. Then use `yarn init` (`npm init` if that's more your style)
+to initialise a new JavaScript package:
+
+```bash
+$ cd ~/.flipper/custom-plugins/
+$ mkdir sea-mammals
+$ cd sea-mammals
+$ yarn init
+```
+
+When choosing the package name, remember to use the name we have specified on the native side as ID.
+In our case, that is "sea-mammals". Once done, open the `package.json`. In addition to the name,
+you can also specify a title to show in the Flipper sidebar and an icon to display here. For instance:
+
+```json
+{
+ "name": "sea-mammals",
+ "version": "1.0.0",
+ "main": "index.js",
+ "license": "MIT",
+ "icon": "apps",
+ "title": "Sea Mammals"
+}
+```
+*See [package.json](https://github.com/facebook/flipper/blob/7dae5771d96ea76b75796d3b3a2c78746e581e3f/src/plugins/seamammals/package.json)*
+
+## Building a Table
+
+We have found that one of the most useful things you can do to understand how your app works
+is to give you easy access to the underlying data used to display items on screen. A very
+easy way of doing this is by showing the data in a table. We have optimized for this
+particular use case that makes it dead-simple to expose your data in a table that you
+can sort, filter and select items for more detailed information.
+
+### Row Types
+
+We start by defining what our table rows look like as types:
+
+```javascript
+type Id = number;
+
+type Row = {
+ id: Id,
+ title: string,
+ url: string,
+};
+```
+
+It is important that you have some unique identifier for every row so
+that we know when something new was added to the table. We will use the
+`id` field here for this purpose.
+
+### Columns
+
+Next, we define which columns to show and how to display them:
+
+```javascript
+const columns = {
+ title: {
+ value: 'Title',
+ },
+ url: {
+ value: 'URL',
+ },
+};
+
+const columnSizes = {
+ title: '15%',
+ url: 'flex',
+};
+```
+
+The keys used here will show up again in the next step when building
+your rows, so keep them consistent. The `value` we define for each column will show up as the header at the top of the table.
+
+For the size you can either choose a fixed proportion or choose `flex`
+to distribute the remaining available space.
+
+### Sidebar
+
+When clicking on an element in your table, you can display a sidebar
+which gives more detail about an object than what is shown inline in the
+table. You could, for instance, show images that you referenced.
+For this tutorial, however, we will just show the full object by
+using our `ManagedDataInspector` UI component:
+
+```javascript
+function renderSidebar(row: Row) {
+ return (
+
+
+
+ );
+}
+```
+
+You'll notice how the function takes the `Row` type we have defined
+before and returns a React component. What you render in this sidebar is
+entirely up to you.
+
+### Building Rows
+
+In the same way that we create our sidebar from a `Row`, we
+also render individual rows in our table but instead of a React
+component, we provide a description of the data based
+on the column keys we have set up before.
+
+```javascript
+function buildRow(row: Row): TableBodyRow {
+ return {
+ columns: {
+ title: {
+ value: {row.title},
+ filterValue: row.title,
+ },
+ url: {
+ value: {row.url},
+ filterValue: row.url,
+ },
+ },
+ key: row.id,
+ copyText: JSON.stringify(row),
+ filterValue: `${row.title} ${row.url}`,
+ };
+}
+```
+
+The `title` and `url` fields correspond to the keys
+we have previously set up as part of the `columns`
+object.
+
+`filterValue` is used to power the search bar at the top
+of the table. Defining `copyText` allows you to come up
+with a serialization scheme so users can right-click on
+any row and copy the content to their clipboard.
+
+### Putting it all to work
+
+Now that we've build all the individual pieces, we
+just need to hook it all up using `createTablePlugin`:
+
+```javascript
+export default createTablePlugin({
+ method: 'newRow',
+ columns,
+ columnSizes,
+ renderSidebar,
+ buildRow,
+});
+```
+*See [index.js](https://github.com/facebook/flipper/blob/7dae5771d96ea76b75796d3b3a2c78746e581e3f/src/plugins/seamammals/index.js)*
+
+The `method` we define here corresponds to the name
+of the function we call on the native side to inform
+the desktop about new data we want to display.
+
+And that's it! Starting Flipper will now compile your
+plugin and connect to the native side. It's a good
+idea to start Flipper from the command line to see
+any potential errors. The console in the DevTools
+is a great source of information if something doesn't
+work as expected, too.
+
+## What's next?
+
+You now have an interactive table that you can sort,
+filter and use to get additional information about
+the stuff you see on screen.
+
+For many cases, this is already all you need. However,
+sometimes you want to go the extra mile and want
+to build something a bit more custom. That's what
+we're going to do in the next part of our tutorial.
\ No newline at end of file
diff --git a/website/i18n/en.json b/website/i18n/en.json
index 9d7ad7d8e..569ecf180 100644
--- a/website/i18n/en.json
+++ b/website/i18n/en.json
@@ -127,6 +127,9 @@
},
"tutorial/intro": {
"title": "Intro"
+ },
+ "tutorial/js-table": {
+ "title": "Showing a table"
}
},
"links": {
diff --git a/website/sidebars.json b/website/sidebars.json
index 8efd43478..7a003d56e 100644
--- a/website/sidebars.json
+++ b/website/sidebars.json
@@ -45,7 +45,8 @@
],
"Tutorial": [
"tutorial/intro",
- "tutorial/android"
+ "tutorial/android",
+ "tutorial/js-table"
],
"Other Platforms": [
"extending/new-clients",