diff --git a/help/fr/docs/authorship.md b/help/fr/docs/authorship.md
index 2ad1eb673..5a70546e9 100644
--- a/help/fr/docs/authorship.md
+++ b/help/fr/docs/authorship.md
@@ -19,12 +19,12 @@ rappel), cliquez sur l'action `Définir une formule d'initialisation`.
![créer une colonne Créé Par](images/formulas/formulas-created-by-convert.png)
-Définissez `user.Name`{ : .formula} comme formule de la colonne. Il existe
-d'autres possibilités, comme `user.Email`{ : .formula}, ou `user.UserID`{ :
+Définissez `user.Name`{: .formula} comme formule de la colonne. Il existe
+d'autres possibilités, comme `user.Email`{: .formula}, ou `user.UserID`{:
.formula}, etc. Les informations disponibles sur l'utilisateur sont les mêmes
que dans les [Permissions Avancées](access-rules.md#access-rule-conditions).
L'horodatage est également disponible (voir [Colonnes
-d'horodatage](timestamps.md)). Mais restons-en à `user.Name`{ : .formula} pour
+d'horodatage](timestamps.md)). Mais restons-en à `user.Name`{: .formula} pour
l'instant.
![une colonne Créé par](images/formulas/formulas-created-by-final.png)
@@ -37,7 +37,7 @@ créée, la colonne `Créé par` aura le nom de l'utilisateur qui a créé cette
![un exemple Créé par](images/formulas/formulas-created-by-autofill.png)
-## Une colonne "Mis à jour par"
+## Une colonne "Dernière mise à jour par"
Si nous voulons une colonne qui enregistre le nom de la dernière personne qui a
modifié une ligne (par opposition à la personne qui a créé la ligne), la
@@ -50,15 +50,17 @@ et appuyez sur `OK`. Par ailleurs, vous pouvez également choisir que certaines
colonnes en particulier qui, lorsqu'elles seront mises à jour, déclencheront la
formule.
-![une colonne Mise à jour par](images/formulas/formulas-updated-by-setup.png)
+![Une colonne "Dernière mise à jour
+par"](images/formulas/formulas-updated-by-setup.png)
Voici un exemple de la nouvelle colonne à l'œuvre - lorsque `Cotton Candy v
Candy Floss` est mise à jour, un nom d'utilisateur apparaît pour cette ligne :
-![une colonne Mise à jour par](images/formulas/formulas-updated-by-autofill.png)
+![Une colonne "Dernière mise à jour
+par"](images/formulas/formulas-updated-by-autofill.png)
-!!! note "Il est toujours possible pour un utilisateur de modifier manuellement
-les cellules dans les colonnes `Créé par` et `Mis à jour par`. Si vous ne voulez
-pas que cela soit autorisé, utilisez les [Permissions Avancées](access-rules.md)
-pour l'interdire."
+!!! note "" **Il est toujours possible pour un utilisateur de modifier
+manuellement des cellules dans les colonnes `Créé par` ou `Dernière mise à jour
+par`. Si vous ne souhaitez pas le permettre, utilisez [les règles
+d'accès](access-rules.md) pour l'interdire.**
diff --git a/help/fr/docs/index.md b/help/fr/docs/index.md
index 93741416f..10b46739a 100644
--- a/help/fr/docs/index.md
+++ b/help/fr/docs/index.md
@@ -1,16 +1,7 @@
-!!!warning
+# Bienvenue sur Grist ! {: data-toc-label='' }
- Nous commençons tout juste à traduire la documentation pour cette langue, désolé !
-
- Nous affichons des pages traduites partiellement de sorte de suivre l'avancement.
-
- Cette page n'est pas encore traduite. Mais la bonne nouvelle est que [vous pouvez rejoindre la communauté de traduction pour nous aider 👋](https://hosted.weblate.org/engage/grist-help/){.internal-link target=_blank}.
-
-
-
-# Welcome to Grist! {: data-toc-label='' }
-
-[Grist](https://www.getgrist.com) is a software product to organize, analyze, and share data.
+[Grist](https://www.getgrist.com) est une solution pour organiser, analyser et
+partager des données.
@@ -34,49 +26,58 @@ Intro videos.
### How-To Tutorials
-[Create a custom CRM](lightweight-crm.md). Using the "Lightweight CRM" example,
-learn to link data, and create high-productivity layouts.
+[Créer un CRM personnalisé](lightweight-crm.md). En utilisant l'exemple "CRM
+léger" ("Lightweigth CRM"), apprenez à lier les données entre elles, et à créer
+des agencements pour une bonne performance.
-[Analyze and visualize data](investment-research.md). Using the "Investment
-Research" example, learn to create summary tables and charts, and link charts dynamically.
+[Analysez et visualiser les donnéès](investment-research.md). En utilisant
+l'exemple "Investment Research" ("Recherche en matière d'investissement"),
+apprenez à créer des tables de résumé et des graphiques, et à lien les
+graphiques dynamiquement entre eux.
-[Managing business data](afterschool-program.md). Using the "Afterschool Program" example,
-learn to model business data, use formulas, and manage complexity.
+[Managing business data](afterschool-program.md). Using the "Afterschool
+Program" example, learn to model business data, use formulas, and manage
+complexity.
-### Intro Videos
+### Vidéos d'introduction
-[![Creating a doc](https://img.youtube.com/vi/eL0EU_Fv_TI/0.jpg) *Creating a doc*](creating-doc.md)
+[![Créer un document](https://img.youtube.com/vi/eL0EU_Fv_TI/0.jpg) *Créer un
+document*](creating-doc.md)\
{: .img-caption }
-[![Pages & widgets](https://img.youtube.com/vi/vTfOUEFR73Y/0.jpg) *Pages & widgets*](page-widgets.md)
+[![Pages & vues](https://img.youtube.com/vi/vTfOUEFR73Y/0.jpg) *Pages &
+vues*](page-widgets.md)\
{: .img-caption }
-[![Columns & types](https://img.youtube.com/vi/kEKYcW3h4V8/0.jpg) *Columns & types*](col-types.md)
+[![Colonnes & types](https://img.youtube.com/vi/kEKYcW3h4V8/0.jpg) *Colonnes &
+types*](col-types.md)\
{: .img-caption }
-[![Reference columns](https://img.youtube.com/vi/fkn2YCxEvTc/0.jpg) *Reference columns*](col-refs.md)
+[![Les colonnes Référence](https://img.youtube.com/vi/fkn2YCxEvTc/0.jpg) *Les
+colonnes Référence*](col-refs.md)\
{: .img-caption }
-[![Linking widgets](https://img.youtube.com/vi/F5m_je0QKvs/0.jpg) *Linking widgets*](linking-widgets.md)
+[![Lier les vues entre elles](https://img.youtube.com/vi/F5m_je0QKvs/0.jpg)
+*Lier les vues entre elles*](linking-widgets.md)\
{: .img-caption }
-[![Sharing a doc](https://img.youtube.com/vi/vJpcC3-FHF8/0.jpg) *Sharing a doc*](sharing.md)
+[![Partager un document](https://img.youtube.com/vi/vJpcC3-FHF8/0.jpg) *Partager
+un document*](sharing.md)\
{: .img-caption }
-## Popular shortcuts
+## Raccourcis populaires
-- [Frequently Asked Questions](FAQ.md)
+- [Foire Aux Questions](FAQ.md)
- [Function reference](functions.md)
-- [Keyboard shortcuts](keyboard-shortcuts.md)
-
+- [Raccourcis clavier](keyboard-shortcuts.md)
-## Contact us
+## Nous contacter
-If you have questions not answered here, problem reports, or other feedback,
-please contact us!
+Si vous avez des questions dont vous ne trouvez pas la réponse ici, si vous
+souhaitez remonter des problèmes ou d'autres retours, merci de nous contacter !
-Email:
+Email :
diff --git a/help/fr/docs/widget-custom.md b/help/fr/docs/widget-custom.md
new file mode 100644
index 000000000..cf0eea82a
--- /dev/null
+++ b/help/fr/docs/widget-custom.md
@@ -0,0 +1,973 @@
+# Page vue : Custom
+
+La vue **Custom** permet à un utilisateur d'insérer presque tout dans son
+document. Créer une vue personnalisée nécessite pour l'instant des connaissance
+en développement web, et l'accès à un serveur web public (par exemple les GitHub
+Pages).
+
+Un cas d'usage puissant pour les vues personnalisées est de consulter des lignes
+ou des tables de manières inédites en utilisant Grist comme votre modèle de
+données et du HTML/CSS/JS moderne comme vue.
+
+## Exemple minimal
+
+Pour illustrer le fonctionnement des vues custom à une développeuse web, un
+exemple minimal se trouve sur :
+
+>
+
+L'exemple montre une table avec de la donnée aléatoire (des noms d'animaux de
+compagnie) et deux vues custom, une montrant la ligne sélectionnée en JSON, et
+l'autre montrant toutes les lignes de la table en JSON. Si vous changez la
+donnée dans la table, ou déplacez le curseur, les vues custom se mettent à jour.
+
+![exemple de vue custom](images/widget_custom_example.png)
+
+Le code source de la vue est sur :
+
+>
+
+Il est simplifié au maximum. Voici le code source complet de la vue `onRecord`
+qui montre une ligne de données :
+
+
+```html
+
+
+
+
+ onRecord
+
+
+
+ Waiting for data...
+
+
+
+```
+
+Les parties "Grist" du code sont :
+
+* Inclure `https://docs.getgrist.com/grist-plugin-api.js` pour récupérer l'API
+ Grist.
+* Appeler `grist.ready` pour dire à Grist que le widget est prêt à démarrer.
+* Appeler `grist.onRecord` pour s'abonner à la ligne actuellement sélectionnée
+ de la table.
+
+Tout le reste est du HTML/CSS/JS standard. Une fois que vous avez la donnée en
+entrée, vous pouvez l'afficher de la manière qui vous chante, en utilisant
+React, Vue.js, ou votre framework favori. Par exemple, vous pourriez afficher la
+donnée comme une [facture imprimable](examples/2020-08-invoices.md), ou dans un
+format de graphique obscur que Grist ne supporte pas encore.
+
+## Ajouter une vue custom
+
+Pour ajouter une vue custom qui lit de la donnée depuis une table, cliquez sur
+`Nouveau` puis `Ajouter une vue à la page`. Puis :
+
+* Pour `Choisir la vue` choisissez `Personnalisée` pour récupérer une vue
+ personnalisée.
+* Pour `Choisir les données source` choisissez la table dont vous voulez que la
+ vue lise le contenu.
+* Vous pouvez aussi choisir `Sélectionner par` pour encore plus controller la
+ donnée sélectionnée (lire [Lier des vues](linking-widgets.md) pour les
+ possibilités).
+
+![ajouter une vue personnalisée](images/widget_custom_add.png)
+
+La vue personnalisée est d'abord vide. Pour la configurer, cliquez sur les trois
+points en haut à droite de la vue et sélectionnez "Options de la vue".
+
+![configurer une vue personnalisée](images/widget_custom_example.png)
+
+Dans la section `CUSTOM` des paramètres, là ou il est affiché `Enter Custom
+URL`, mettez le lien vers votre vue personnalisée. Voici une vue test pour
+montrer s'implement les données de la table en JSON :
+
+>
+
+And here's one to show the selected row only (make sure "Select By" is set for
+the custom widget):
+
+>
+
+## Access level
+
+When you put a link to a custom webpage it will be immediately rendered inside
+the section. Now you have the option to grant that webpage access to data in
+your document. The following access levels are available:
+
+- *No document access*: the webpage is shown in the widget, but it has no access
+ to the Grist document containing the widget.
+- *Read selected table*: the webpage is shown in the widget, and is given read
+ access to the table the widget is configured to select data from.
+- *Full document access*: the webpage is shown in the widget, and has full
+ access to read and modify the Grist document containing the widget.
+
+The webpage should be owned and controlled by you or someone you trust. With
+`Read selected table` permissions, a widget could send the data it accesses to a
+third party. With `Full document access` permissions, a widget could send all
+the document data to a third party, and modify your document in any way.
+
+If you are writing your own custom widget you can specify what access level it
+needs as part of the initial **ready** message. Possible values are: `none`,
+`read table` and `full`.
+
+```html
+
+```
+
+This directs Grist to request the desired access level from the user. Your
+widget will be reloaded with the appropriate access level if the user approves
+the request.
+
+*![access
+prompt](images/widget_custom_access_prompt.png)* {: .screenshot-half }
+
+If you wish to get notified of the access level, you can subscribe to the
+`onOptions` event that is sent to the widget after it tells Grist it is ready:
+
+```javascript
+grist.onOptions(function(options, interaction) {
+ console.log(interaction.access_level);
+});
+```
+
+For now, just skip the `options` parameter (it will be described in [Widget
+options](widget-custom.md#widget-options) section). The current access level is
+part of the second parameter, which describes how Grist will interact with your
+widget.
+
+## Invoice example
+
+The minimal example above showed records as plain JSON, but the widget can get
+as fancy as you like. Here is an example of showing a record as a printable
+invoice:
+
+![invoice example](examples/images/2020-08-invoices/final-invoice.png)
+
+You can read the details of how to use this widget in our [Invoice preparation
+example](examples/2020-08-invoices.md). The invoice widget is hosted at:
+
+>
+
+And the source HTML/CSS/JS can be browsed at:
+
+>
+
+It uses Vue.js and `grist.onRecord`.
+
+## Creating a custom widget
+
+As you saw, writing a simple widget that uses data from a table is very easy.
+First, you need to tell Grist that you are ready and then subscribe to one of
+the available events: `onRecord`, `onRecords` or `onOptions`.
+
+```javascript
+grist.ready();
+grist.onRecord(function (record) {
+ // Cursor has moved.
+});
+grist.onRecords(function (record) {
+ // Data in the table has changed.
+});
+grist.onOptions(function (options, interaction) {
+ // Configuration has changed.
+});
+```
+
+Let's say you want to build a custom widget that will show an image from a URL
+and optionally a single line of text below as the image title. You will need to
+read two values from two columns: `Link` and `Title`.
+
+You could access those columns directly using literal column names in your
+script. Here is a complete example of widget source code that will do the job:
+
+```html
+
+
+
+
+```
+
+When getting started, this is a good approach, but it has two significant
+drawbacks. Every time you rename a column, you will also have to change your
+widget's source. Moreover, using this widget on a different table or sharing it
+with your friends can be difficult as column names might be different. To help
+with this, Grist offers the column mapping API.
+
+## Column mapping
+
+Instead of using column names directly, you can ask the user to pick which
+column to use as a `Link` and `Title`. The list of expected columns can be sent
+to Grist as part of the ready call:
+
+```js
+grist.ready({columns: ['Link', 'Title']});
+```
+
+Using this information, in the creator panel, Grist will hide the regular
+"Visible" columns section and display specialized column pickers.
+
+*![access
+prompt](images/widget_custom_pick_columns.png)* {: .screenshot-half }
+
+Your widget will receive this mapping configuration as part of `onRecord` or
+`onRecords` event in the second parameter. You can use this configuration to do
+the mappings yourself or use the `mapColumnNames` helper function to do it for
+you.
+
+```html
+
+
+
+
+```
+
+Now, if you rename one of the columns, the widget will still work. You can also
+use this widget in any other table or share with a friend, as it doesn't depend
+on your table structure and can be easily configured.
+
+In the configuration used above, we told Grist that all the columns are
+required, and the user can pick any column even if the column doesn't contain a
+text value. To be more precise, we can include more options in the request. For
+example:
+
+```javascript
+grist.ready({columns: [
+ {
+ name: "Link", // What field we will read.
+ title: "Image link", // Friendly field name.
+ optional: false, // Is this an optional field.
+ type: "Text" // What type of column we expect.
+ description: "Some text" // Description of a field.
+ allowMultiple: false // Allows multiple column assignment.
+ }
+]});
+```
+
+The `optional` setting is important for correct operation of the
+`mapColumnNames` helper. This helper will return a mapped record only when all
+required (not optional) columns are picked.
+
+By default Grist will allow the user to pick any type of column. To allow only a
+column of a specific type, you need to set a `type` property. Here are all valid
+types:
+
+`Int` (*Integer column*), `Numeric` (*Numeric column*), `Text`, `Date`,
+`DateTime`, `Bool` (*Toggle column*), `Choice`, `ChoiceList`, `Ref` (*Reference
+column*), `RefList` (*Reference List*), `Attachments`.
+
+The default value of `type` is `Any`, so Grist will allow the user to pick any
+column type. You can also specify a list of types, for example `Date,DateTime`.
+In that case, Grist will allow the user to pick any column that matches one of
+the types in the list.
+
+Use `title` and `description` fields to help your users understand what is the
+purpose of the column. The `description` will be displayed just below the column
+name, and the `title` will be used as a column label. Both are optional and you
+can put there any text you want.
+
+If you need to map multiple columns (for example in a custom chart widget), you
+can use `allowMultiple` option. This will allow your users to pick a set of
+columns that will be returned as list of mapped table column names. The
+`mapColumnNames` helper will then return an array of mapped column values in a
+single field.
+
+Suppose the user deletes a column or changes its type so that it will no longer
+match the type requested by the widget. In that case, Grist will automatically
+remove this column from the mapping.
+
+## Widget options
+
+If your widget needs to store some options, Grist offers a simple key-value
+storage API for you to use. Here are some JavaScript code snippets that show how
+to interact with this API:
+
+```js
+// Store a simple text value .
+await grist.setOption('color', '#FF0000');
+
+// Store complex objects as JSON.
+await grist.setOption('settings', {lines: 10, skipFirst: true});
+
+// Read previously saved option
+const color = await grist.getOption('color');
+
+// Clear all options.
+await grist.clearOptions();
+
+// Get and replace all options.
+await grist.getOptions();
+await grist.setOptions({...});
+```
+
+You can experiment with this yourself. Here is a test widget that demonstrates
+how to use this API:
+
+>
+
+When your widget saves or edits some options, the icon on top of the section
+gets highlighted in green. You can either apply those options to the widget or
+revert that modification.
+
+*![unsaved
+options](images/widget_custom_unsaved_options.png)* {: .screenshot-half }
+
+This allows viewers (users with read-only access) or collaborators to configure
+your widget without overwriting original settings. This behavior should look
+familiar to you and others, as this works like [sorting and
+filtering](search-sort-filter.md#saving-sort-settings) on table or card views.
+
+Saving current options you will apply them to the widget and make them available
+to others. Using this menu, you can also clear all options to revert the widget
+to its initial state. To do this, press the little trash icon and then `Save`.
+
+Grist will also trigger an event, every time the options are changed (or
+cleared). Here is how you can subscribe to this event.
+
+```javascript
+grist.onOptions(function(options, interaction) {
+ if (options) {
+ console.log('Current color', options.color);
+ } else {
+ // No widget options were saved, fallback to default ones.
+ }
+});
+```
+
+If you are building your own widget, you generally should not read options
+directly (using `grist.widgetApi.getOption()`). A better pattern is to apply
+them all when they are changed. Using the `onOptions` handler will make your
+widget easier to change and understand later.
+
+There is one more scenario to cover. Suppose your widget has some kind of custom
+configuration screen. In that case, you probably need some button or other UI
+element that the user can use to show it. This additional UI element will likely
+be rarely used by you or your collaborators, so it doesn't make sense to show it
+all the time. To help with this, Grist offers an additional interaction option
+you can send as part of the ready message:
+
+```javascript
+grist.ready({
+ onEditOptions: function() {
+ // Your custom logic to open the custom configuration screen.
+ }
+});
+```
+
+This will tell Grist to display an additional button `Open configuration` in the
+creator panel and the section menu. When clicked, it will trigger your handler,
+which you can use to show your own custom configuration screen.
+
+*![unsaved
+options](images/widget_custom_open_configuration.png)* {:
+.screenshot-half }
+
+
+## Custom Widget linking
+
+Custom widgets can also be used as a source of linking (see [Linking
+widgets](linking-widgets.md)). All you need to do is inform Grist that your
+widget supports linking by passing an additional option to the `ready` call (see
+[Widget API](./code/modules/grist_plugin_api.md#ready)):
+
+```javascript
+grist.ready({
+ allowSelectBy: true
+});
+```
+
+This will enable the `Select By` option in the widget configuration panel. Now
+you can use your widget to control the cursor position in linked widgets. To do
+this, you need to call the `setCursorPos` function:
+
+```javascript
+// Inform Grist that the cursor should be moved to the row with id 20.
+grist.setCursorPos({rowId: 20});
+
+// or inform that your widget is creating a new row.
+grist.setCursorPos({rowId: 'new'});
+```
+
+
+
+## Premade Custom Widgets
+
+All premade custom widgets are available in the Custom Widget configuration
+panel on the right-hand side of the screen under the Custom dropdown.
+
+*![premade-widgets](images/widget-custom/premade-widgets.png)*
+{: .screenshot-half }
+
+### Advanced Charts
+
+The Advanced Charts custom widget gives you more power and flexibility than
+Grist’s built-in charts, offering a wide variety of chart types as well as
+increased control over styling and layout. It’s a version of Plotly’s [Chart
+Studio](https://chart-studio.plotly.com/), see their
+[tutorials](https://plotly.com/chart-studio-help/tutorials/) for more detailed
+help.
+
+You’ll need to set the access level to “Full document access”. Don’t worry, the
+widget only reads data from the selected table, doesn’t send it to any servers,
+and doesn’t write or otherwise make changes back to your document.
+
+This is what you should see:
+
+![advanced-chart-blank-traces-panel](./images/widget-custom/advanced-chart-blank-traces-panel.png)
+
+Click the big blue “+ Trace” button to get started. This will add a panel like
+the following:
+
+![advanced-chart-blank-trace](./images/widget-custom/advanced-chart-blank-trace.png)
+
+Click “Scatter” to choose a different chart type such as Bar or Line. Then click
+the “Choose data” dropdowns to select the columns you want to plot.
+
+You can add multiple traces to overlay different plots. Try different panels
+from the sidebar to customize the chart further. For example, go to Style > Axes
+> Titles to add a label to each axis. See the [chart studio
+tutorials](https://plotly.com/chart-studio-help/tutorials/) to learn more.
+
+As you customize the widget, remember to regularly click the ‘Save’ button above
+the widget to keep your configuration.
+
+### Copy to clipboard
+
+Copy to clipboard copies a value from the specified column of the selected
+record. When configuring the widget, you will need to select which column you
+wish to copy data from.
+
+*![copy-to-clipboard](images/widget-custom/copy-to-clipboard.png)*
+
+Note that you can also copy data from a selected cell by using the keyboard
+shortcut *Ctrl* + *C*
on Windows or
+*⌘* + *C*
on Mac. To paste, use
+*Ctrl* + *V*
or *⌘* + *V*
.
+
+You can find an example of the copy to clipboard button in our [Webinar 7
+(Custom
+Widgets)](https://public.getgrist.com/uGS3WH3mhoVy/7-Webinar-7-Custom-Widgets-End-Result/p/4){:target="\_blank"}
+template. You can also watch a video walkthrough from our [Custom Widgets
+Webinar](https://www.youtube.com/watch?v=zNLHX_ezY50&t=2063s){:target="\_blank"}.
+
+### Dropbox Embedder
+
+View and access files saved to dropbox.
+
+*![dropbox-embedder-widget](images/widget-custom/dropbox-embedder-widget.png)*
+{: .screenshot-half }
+
+To start, add a new column to your table to store your dropbox links.
+
+Then, add a new custom widget to the page. Choose the data table that contains
+the dropbox links and 'Select By' that same table.
+
+*![dropbox-add-widget](images/widget-custom/dropbox-add-widget.png)*
+{: .screenshot-half }
+
+To configure, select 'Dropbox Embedder' from the Custom dropdown and allow
+access to read the selected table. Under 'Dropbox Link', select the column that
+contains your dropbox links.
+
+*![dropbox-embedder-configuration](images/widget-custom/dropbox-embedder-configuration.png)*
+{: .screenshot-half }
+
+You can create links to folders or specific files in Dropbox. Click 'Share' then
+set permissions for the link. You can choose to allow anyone with the link to
+view or edit. Create, then copy the link. Paste this link into your Dropbox Link
+column in Grist. Note that users cannot edit directly in the custom widget even
+if edit permissions are granted. To edit, select the object in the Dropbox
+Embedder and it will open in a new tab where it can be edited directly in
+Dropbox.
+
+*![dropbox-embedder-create-link](images/widget-custom/dropbox-embedder-create-link.png)*
+
+You can check out an example of the Dropbox Embedder in our [Hurricane
+Preparedness](https://templates.getgrist.com/uXMbETLdfriM/Hurricane-Preparedness){:target="\_blank"}
+template.
+
+*![dropbox-embedder](images/widget-custom/dropbox-embedder.png)*
+
+### Grist Video Player
+
+Embed videos from online sources like YouTube, Vimeo, Facebook Video, Google
+Drive and more.
+
+*![video-player](images/widget-custom/video-player.png)*
+
+To start, add a new column to your table to store your video URLs.
+
+Then, add a new custom widget to the page. Choose the data table that contains
+the video URLs and 'Select By' that same table.
+
+*![video-player-add-widget](images/widget-custom/video-player-add-widget.png)*
+{: .screenshot-half }
+
+To configure, select 'Grist Video Player' from the Custom dropdown and allow
+access to read the selected table. Under 'URL', select the column that contains
+your video URLs.
+
+*![video-player-configuration](images/widget-custom/video-player-configuration.png)*
+{: .screenshot-half }
+
+For most online videos, including YouTube videos and videos stored on Google
+Drive, you can simply click the 'Share' option and copy the URL.
+
+*![youtube-embed](images/widget-custom/youtube-embed.png)*
+
+For some other videos, you may see this error:
+
+*![video-player-error](images/widget-custom/video-player-error.png)*
+
+If this happens, you'll need to take the URL from the Embed code.
+
+After clicking the share option on the video, click the option to 'Embed'.
+
+*![video-facebook-embed](images/widget-custom/video-facebook-embed.png)*
+
+Then, click to copy the code.
+
+*![video-facebook-embed-2](images/widget-custom/video-facebook-embed-2.png)*
+
+The code it gives you will look something like this:
+
+*![video-facebook-embed-code](images/widget-custom/video-facebook-embed-code.png)*
+
+Copy the URL that is found between quotes following `src`. The highlighted
+portion in the screenshot below is what you would copy for this particular
+Facebook video.
+
+*![video-facebook-embed-src](images/widget-custom/video-facebook-embed-src.png)*
+
+Paste this URL into your URL column in Grist and the video will now appear in
+the Grist Video Player custom widget.
+
+*![video-player-embed](images/widget-custom/video-player-embed.png)*
+
+### HTML Viewer
+
+The HTML viewer displays HTML written in a cell.
+
+For text-editing widgets, check out our [Markdown](#markdown) and
+[Notepad](#notepad) custom widgets.
+
+*![html-viewer](images/widget-custom/html-viewer.png)*
+
+To start, add a new column to your table. This will be where you add you write
+HTML.
+
+Then, add a new custom widget to the page. Choose the data table that contains
+the HTML and 'Select By' that same table.
+
+*![html-viewer-add-widget](images/widget-custom/html-viewer-add-widget.png)*
+{: .screenshot-half }
+
+To configure, select 'HTML Viewer' from the Custom dropdown and allow access to
+read the selected table. Under 'HTML', select the text column that contains your
+HTML.
+
+*![html-viewer-configurationt](images/widget-custom/html-viewer-configuration.png)*
+{: .screenshot-half }
+
+Your HTML will be viewable in the custom widget.
+
+*![html-viewer-final-example](images/widget-custom/html-viewer-final-example.png)*
+
+For help on HTML formatting, check out this guide from W3 Schools: [HTML Text
+Formatting](https://www.w3schools.com/html/html_formatting.asp){:target="\_blank"}
+
+You can find an example of the HTML Viewer in our [Webinar 7 (Custom
+Widgets)](https://public.getgrist.com/uGS3WH3mhoVy/7-Webinar-7-Custom-Widgets-End-Result/p/1){:target="\_blank"}
+template. You can also watch a video walkthrough from our [Custom Widgets
+Webinar](https://www.youtube.com/watch?v=zNLHX_ezY50&t=1538s){:target="\_blank"}.
+
+### Image Viewer
+
+View images from URL.
+
+*![image-viewer](images/widget-custom/image-viewer.png)*
+
+To start, add a new column to your table. This will be where you add the URL for
+your image.
+
+Then, add a new custom widget to the page. Choose the data table that contains
+the image URL and 'Select By' that same table.
+
+*![image-viewer-add-widget](images/widget-custom/image-viewer-add-widget.png)*
+{: .screenshot-half }
+
+To configure, select 'Image Viewer' from the Custom dropdown and allow access to
+read the selected table. Under 'Image URL', select the column that contains the
+URLs for your images.
+
+*![image-viewer-configuration](images/widget-custom/image-viewer-configuration.png)*
+{: .screenshot-half }
+
+To copy the URL for an image, right click on the photo then 'Copy image
+address'. This copies the URL to your clipboard. Paste this URL into your
+specified column in Grist.
+
+*![image-viewer-save-image](images/widget-custom/image-viewer-save-image.png)*
+
+Additionally, you can add multiple images for a specific record by adding
+multiple image URLs, separated by a space or new line, into a single cell.
+
+Please note that a comma will not work to separate the links.
+
+*![image-viewer-multiple-links](images/widget-custom/image-viewer-multiple-links.png)*
+
+When multiple image URLs are present, the image viewer custom widget will
+function as a carousel. Click the arrows to view additional images.
+
+*![image-viewer-park-multiple](images/widget-custom/image-viewer-multiple.png)*
+{: .screenshot-half }
+
+For an example of the Image Viewer widget, check out our [U.S. National Park
+Database](https://templates.getgrist.com/4TRbjZXSPtR5/US-National-Park-Database/p/4){:target="\_blank"},
+and add a park review while you're there!
+
+You can also check out our [Meme
+Generator](https://templates.getgrist.com/gtzQwTXkgzFG/Meme-Generator){:target="\_blank"}
+template for another great example.
+
+For a video walkthrough, be sure to watch our [Custom Widgets
+Webinar](https://www.youtube.com/watch?v=zNLHX_ezY50&t=559s){:target="\_blank"}!
+
+### JupyterLite Notebook
+
+This widget lets you run custom Python code in
+[JupyterLite](https://jupyterlite.readthedocs.io/), a version of
+[JupyterLab](https://jupyterlab.readthedocs.io/en/stable/index.html) running
+entirely in the browser. You can use the full [custom widget plugin
+API](./code/modules/grist_plugin_api.md) and access or modify any data in the
+document (subject to Access Rules), unlocking nearly unlimited possibilities for
+advanced users.
+
+You’ll be presented with a notebook where you can enter and run Python code,
+e.g:
+
+![jupyterlite-notebook-example-notebook](./images/widget-custom/jupyterlite-notebook-example-notebook.png)
+
+After typing code in a cell, click the play button or press Shift+Enter to run
+that cell.
+
+Unlike formulas, code isn’t saved automatically. You must press the usual ‘Save’
+button above the widget (outside the notebook) to persist the code within your
+Grist document. On the other hand, changes to settings within the notebook (e.g.
+keyboard shortcuts) are saved in your browser’s local storage, so they’re not
+shared with other users of the document.
+
+A special object called `grist` is automatically available to use in Python
+code, which mirrors many common methods of the usual [JS plugin
+API](./code/modules/grist_plugin_api.md). Note that many of these methods are
+asynchronous, so you should use `await` before calling them.
+
+- `async fetch_selected_table()`: returns the data of the table backing the
+ notebook widget.
+- `async fetch_selected_record(row_id=None)`: returns a record of the table
+ backing the notebook widget. If `row_id` is specified, returns the record at
+ that row. Otherwise, returns the record at the current cursor position in a
+ widget linked to the notebook widget.
+- `async fetch_table(table_id)`: returns the data of the specified table. Note
+ that this differs from `fetch_selected_table` (even for the same table) in
+ several ways:
+ - The widget must have full document access.
+ - All columns are included, whereas `fetch_selected_table` excludes columns
+ that are hidden in the widget configuration.
+ - All rows are included, whereas `fetch_selected_table` takes widget filters
+ and 'SELECT BY' into account.
+ - The data is not sorted according to the widget's configuration.
+ - The data is fetched from the server, so the method may be slower.
+ - The values for reference columns are row IDs of the referenced table,
+ whereas `fetch_selected_table` returns the values displayed based on the
+ 'SHOW COLUMN' configuration.
+- `on_record(callback)`: registers a callback function to run when the cursor
+ moves in a widget linked to the notebook widget, i.e. the widget chosen from
+ the "SELECT BY" dropdown in the Data section of the widget configuration. The
+ callback function will be passed the record at the current cursor position.
+ You can also use this as a decorator, i.e. `@grist.on_record`.
+- `on_records(callback)`: similar to `on_record`, but runs when the source data
+ of the widget changes. The callback function will be passed the same data as
+ returned by `fetch_selected_table`.
+- `get_table(table_id)`: returns a `TableOperations` class similar to the
+ interface in the usual [JS plugin
+ API](./code/interfaces/TableOperations.TableOperations.md) for performing
+ CRUD-style operations on a table. See the plugin API documentation for details
+ on the parameters. The class has the following methods:
+ - `async create(records, parse_strings=True)`
+ - `async update(records, parse_strings=True)`
+ - `async upsert(records, parse_strings=True, add=True, update=True,
+ on_many="first", allow_empty_require=False)`
+ - `async destroy(row_ids)`
+
+You can also use `grist.raw` for direct access to the plugin API, e.g. `await
+grist.raw.docApi.fetchTable(table_id)`. This may return raw cell values which
+you can decode with `grist.decode_cell_value(value)`.
+
+You can use many (but not all) third-party libraries in your notebook such as
+`pandas`. Many will be installed automatically when they're imported. Others
+will require running `%pip install ` in a cell, e.g. `%pip install
+pandas`. Note that it's `%pip` and not `!pip` as in a regular Jupyter notebook.
+
+### Map
+
+The custom map widget allows you to display locations using latitude and
+longitude coordinates. If your data is an address, rather than in lat-long
+format, Grist can convert the address into lat-long coordinates.
+
+*![map-widget](images/widget-custom/map-widget.png)*
+
+If using existing lat-long coordinates, you will need three columns; Name,
+Longitude and Latitude.
+
+*![map-lat-long-columns](images/widget-custom/map-lat-long-columns.png)*
+{: .screenshot-half }
+
+If using an address, you will need six columns; Name, Address, Geocode,
+Longitude, Latitude, and Geocoded Address.
+
+*![map-address-columns](images/widget-custom/map-address-columns.png)*
+
+Geocode is a [toggle type column](col-types.md#toggle-columns) that should be
+set to true for any record you wish to convert from address to lat-long
+coordinates to be shown on the map.
+
+If you wish to convert all records, you can make Geocode a formula column with
+the formula = `True`. This will mark all records as True.
+
+*![map-geocode-true](images/widget-custom/map-geocode-true.png)*
+{: .screenshot-half }
+
+Next, add a new custom widget to the page. Choose the data table that contains
+the addresses or lat-long coordinates and 'Select By' that same table.
+
+*![map-add-widget](images/widget-custom/map-add-widget.png)*
+{: .screenshot-half }
+
+To configure, select 'Map' from the Custom dropdown.
+
+If you already have **lat-long coordinates**, you can set your access level to
+*Read selected table*.
+
+If you are using an **address** and that needs to be converted into lat-long
+coordinates, you will need to set your access level to *Full document access*
+because the widget needs permission to write to your document in order to add
+lat-long coordinates.
+
+*![map-configuration-1](images/widget-custom/map-configuration-1.png)*
+{: .screenshot-half }
+
+Map all required columns. Note that Name, Longitude and Latitude are labeled as
+required. Geocode, Address and Geocoded Address are listed as optional. If you
+are using addresses and need Grist to convert these to lat-long coordinates, you
+must map all six columns.
+
+*![map-configuration-2](images/widget-custom/map-configuration-2.png)*
+{: .screenshot-half }
+
+After mapping the necessary columns and selecting the appropriate Access Level,
+the map widget will populate.
+
+*![map-final](images/widget-custom/map-final.png)*
+
+You can configure the map to show only the selected location by clicking the
+'Open Configuration' option in the [creator panel](glossary.md#creator-panel).
+Then, uncheck 'All Locations'. Click the green check mark at the top of the
+widget to save the updated configuration settings.
+
+*![map-configuration-location](images/widget-custom/map-configuration-location.png)*
+
+Check out our [Mapping
+Locations](https://templates.getgrist.com/pyMHqncEspfZ/Mapping-Locations){:target="\_blank"}
+template or our [Crowdsourced
+List](https://templates.getgrist.com/dKztiPYamcCp/Crowdsourced-List/p/1){:target="\_blank"}
+for two great examples!
+
+For a video walkthrough, check out our [Custom Widgets
+Webinar](https://www.youtube.com/watch?v=zNLHX_ezY50&t=713s){:target="\_blank"}.
+
+### Markdown
+
+The Markdown custom widget allows you to format text using Markdown while
+displaying the formatted text in an editable widget.
+
+For other text-editing widgets, check out our [HTML](#html-viewer) and
+[Notepad](#notepad) custom widgets.
+
+*![markdown-widget](images/widget-custom/markdown-widget.png)*
+
+To start, add a new column to your table. This will be where you will add your
+text that will be formatted using Markdown.
+
+Then, add a new custom widget to the page. Choose the data table that contains
+the text formatted with Markdown and 'Select By' that same table.
+
+*![markdown-add-widget](images/widget-custom/markdown-add-widget.png)*
+{: .screenshot-half }
+
+To configure, select 'Markdown' from the Custom dropdown and allow **Full
+document access**. Because the widget is also an editor, it needs permission to
+write to the document.
+
+Under 'Content', select the text column that contains Markdown formatting.
+
+*![markdown-configuration](images/widget-custom/markdown-configuration.png)*
+{: .screenshot-half }
+
+Any Markdown formatting in the specified text column will apply and be viewable
+and editable in the custom widget.
+
+*![markdown-final](images/widget-custom/markdown-final.png)*
+
+To edit the text directly in the widget, click the edit icon. The text will
+revert to display Markdown syntax that can be edited directly in the widget.
+When in edit mode, the edit icon will be replaced with the save icon. Be sure to
+click the save icon to save any changes and return to viewing the formatted
+text.
+
+*![markdown-edit](images/widget-custom/markdown-edit.png)*
+{: .screenshot-half }
+
+For help on Markdown formatting, check out the [Markdown
+Guide](https://www.markdownguide.org/basic-syntax/){:target="\_blank"} for basic
+syntax. This guide is also accessible in the Markdown widget by clicking the
+information icon at the top of the widget. The guide will open in a new tab of
+your browser for easy reference.
+
+You can find an example of the Markdown editor in our [Webinar 7 (Custom
+Widgets)](https://public.getgrist.com/uGS3WH3mhoVy/7-Webinar-7-Custom-Widgets-End-Result){:target="\_blank"}
+template and check out this video walkthrough from our [Custom Widgets
+Webinar](https://www.youtube.com/watch?v=zNLHX_ezY50&t=1339s){:target="\_blank"}.
+
+### Notepad
+
+The Notepad custom widget allows you to format text using a rich text editor.
+
+For other text-editing widgets, check out our [HTML](#html-viewer) and
+[Markdown](#markdown) custom widgets.
+
+*![notepad-widget](images/widget-custom/notepad-widget.png)*
+
+To start, add a new column to your table. This will be where details for our
+formatted text will be stored.
+
+Then, add a new custom widget to the page. Choose the data table that contains
+the column we just added and 'Select By' that same table.
+
+*![notepad-add-widget](images/widget-custom/notepad-add-widget.png)*
+{: .screenshot-half }
+
+To configure, select 'Notepad' from the Custom dropdown and allow **Full
+document access**. Because the widget is also an editor, it needs permission to
+write to the document.
+
+Under 'Content', select the column created to store our formatted text.
+
+*![notepad-configuration](images/widget-custom/notepad-configuration.png)*
+{: .screenshot-half }
+
+If the text column you chose under Content has existing text, that text will
+appear in the Notepad widget, ready to be formatted.
+
+*![notepad-saved-text](images/widget-custom/notepad-saved-text.png)*
+
+Use any of the options shown here to format your text.
+
+*![notepad-symbols](images/widget-custom/notepad-symbols.png)*
+
+As you can see in the screenshot below, the code for the formatted text is not
+useful to see in your table. You will edit text directly in the Notepad widget
+so you can [hide](widget-table.md#column-operations) this column from your data
+table.
+
+*![notepad-edited-text-code](images/widget-custom/notepad-edited-text-code.png)*
+
+Check out our [U.S. National Park
+Database](https://templates.getgrist.com/4TRbjZXSPtR5/US-National-Park-Database/p/13){:target="\_blank"}
+or our [🛒 Grocery List + Meal
+Planner](https://templates.getgrist.com/cMQA7uuBbtMW/-Grocery-List-Meal-Planner/p/3){:target="\_blank"}
+for two great Notepad examples!
+
+You can also check out this video walkthrough from our [Custom Widgets
+Webinar](https://www.youtube.com/watch?v=zNLHX_ezY50&t=1194s){:target="\_blank"}.
+
+### Print Labels
+
+The Print Labels custom widget allows you to customize and print labels directly
+from Grist.
+
+*![print-label](images/widget-custom/print-label.png)*
+
+To start, add a new column to your table. This column will contain the text for
+the label. Optionally, you can add a second column to specify a label count,
+allowing you to print more than one of the same label without having to create
+duplicate records.
+
+Next, add a new custom widget to the page. Choose the data table that contains
+the label details.
+
+*![print-label-add-widget](images/widget-custom/print-label-add-widget.png)*
+{: .screenshot-half }
+
+To configure, select 'Print Labels' from the Custom dropdown and allow access to
+read the selected table. Under 'Label', select the column that contains the text
+to include on the labels. If you wish to print more than one of any labels,
+select the column that contains the number of labels for each record you wish to
+print.
+
+*![print-label-configuration](images/widget-custom/print-label-configuration.png)*
+{: .screenshot-half }
+
+You can select from standard sheet sizes under the dropdown in the upper left of
+the widget. Be sure to save any changes by clicking the green check mark at the
+upper right of the widget.
+
+*![print-label-sheet-configuration](images/widget-custom/print-label-sheet-configuration.png)*
+
+To leave any blank labels at the beginning of the sheet, click the settings icon
+then specify how many labels should be left blank. This is especially helpful if
+a portion of your label sheet has already been used. You can skip the used
+labels and begin printing on your first unused label.
+
+*![print-label-blanks](images/widget-custom/print-label-blanks.png)*
+
+Check out our [Print Mailing
+Labels](https://templates.getgrist.com/9nNr9uQwoXWA/Print-Mailing-Labels){:target="\_blank"}
+template and our [Treasure
+Hunt](https://templates.getgrist.com/ihsZTnKTF7Lr/Treasure-Hunt/p/6){:target="\_blank"}
+template for two great examples!
+
+You can also check out this video walkthrough from our [Custom Widgets
+Webinar](https://www.youtube.com/watch?v=zNLHX_ezY50&t=1749s){:target="\_blank"}.