# Shiny Blog Formatting Conventions
Shiny-specific formatting requirements for blog posts on shiny.posit.co. These conventions are for the Quarto-based Shiny blog.
## Frontmatter Format
Shiny blog posts use Quarto YAML frontmatter with this structure:
```yaml
---
title: Package Name Version
description: &desc |
Brief description of the package and release.
author: "Author Name"
date: "YYYY-MM-DD"
image: &img feature.png
open-graph:
image: *img
description: *desc
twitter-card:
image: *img
description: *desc
---
```
### Required Fields
- **`title`**: Display title (no specific format required, flexible)
- Can be: `"packagename version"`, `"Package Name x.y.z"`, or descriptive
- Examples:
- `"shinyswatch 0.7.0"`
- `"Reintroducing the Shiny Extension for VS Code"`
- `"Branded theming for Shiny for Python apps"`
- **`description`**: Brief summary with YAML anchor for reuse
- Use `&desc` anchor and `|` for multi-line
- Reuse in social media cards with `*desc`
- **`author`**: Author name in quotes (can be single string or array)
- Single: `"Garrick Aden-Buie"`
- Multiple: `["Author One", "Author Two"]`
- **`date`**: ISO format in quotes `"YYYY-MM-DD"`
- **`image`**: Path to featured image (relative to post directory)
### Social Media Cards
Use YAML anchors to avoid repeating the description:
```yaml
description: &desc |
Your description here that will be reused.
open-graph:
description: *desc
twitter-card:
description: *desc
```
The `&desc` creates an anchor, and `*desc` references it.
### Optional But Common Fields
- **`filters`**: Quarto filters to use
- `shinylive` - For embedding Shinylive apps
- `line-highlight` - For highlighting specific lines
- **`engine`**: Quarto engine (`knitr`, `markdown`, `jupyter`)
- **`freeze`**: Set to `true` if the post includes *any* computational output
- **`format`**: HTML format options
- `code-link: true` - Enable code linking
- `anchor-sections: true` - Enable section anchors
- `reference-location: document` or `section` - Where to place footnotes
- **`code-annotations`**: Set to `hover` for hover annotations
- **`editor`**: Editor options like `render-on-save: true`
### Image Options
Additional image control fields:
```yaml
image: feature.svg
imagealt: "Alternative text for image"
image-header-disable: true # Don't show image in header
```
### What's NOT Included
Unlike Tidyverse posts, Shiny posts do **not** include:
- `output: hugodown::hugo_document`
- `slug` (filename determines URL)
- `photo.url` and `photo.author` (different image structure)
- Consistent `categories` field (optional, varies by post)
## Title Format
The main title can be flexible:
```markdown
# packagename version
```
Or more descriptive:
```markdown
# Reintroducing the Shiny Extension for VS Code
```
There's less rigid formatting for titles in Shiny posts.
## Lead Paragraphs
Shiny posts may use a lead paragraph div for emphasis:
```markdown
::: lead
**We're excited to announce the new Shiny extension for VS Code!**
:::
```
This creates a larger, emphasized opening paragraph.
## Code Formatting
### For Python Packages
Use bash code blocks for installation:
````markdown
```bash
pip install packagename
```
````
With extras:
````markdown
```bash
pip install "packagename[extra]"
```
````
### For R Packages
Use R code blocks:
````markdown
```r
install.packages("packagename")
```
````
For multiple packages:
````markdown
```r
install.packages(c("shiny", "bslib"))
```
````
### Code Block Attributes
Shiny posts use Quarto code block attributes:
````markdown
```{.python filename="app.py"}
from shiny import App
# code here
```
````
````markdown
```{r install-bslib}
#| eval: false
install.packages("bslib")
```
````
### Line Highlighting
Use `# <<` comments to highlight lines (requires `line-highlight` filter):
````markdown
```{.python filename="app.py"}
from shiny.express import ui
import shinyswatch
ui.page_opts(theme=shinyswatch.theme.darkly) # <<
# rest of code...
```
````
### Code Annotations
With `code-annotations: hover` in frontmatter, you can add annotations:
```python
result = some_function() # <1>
```
```markdown
1. This annotation explains the line above
```
## Tabsets for Multiple Variants
Shiny posts frequently use tabsets to show Express vs Core mode or Python vs R:
````markdown
::: {.panel-tabset .shiny-mode-tabset group="shiny-app-mode"}
#### Express
```{.python filename="app.py"}
from shiny.express import ui
# Express code
```
#### Core
```{.python filename="app.py"}
from shiny import ui
# Core code
```
:::
````
### Nested Tabsets
You can nest tabsets for Before/After within Express/Core:
````markdown
::: {.panel-tabset group="shiny-app-mode"}
#### Express
::: {.panel-tabset}
##### Before
```python
# old code
```
##### After
```python
# new code
```
:::
#### Core
::: {.panel-tabset}
##### Before
```python
# old code
```
##### After
```python
# new code
```
:::
:::
````
## Callouts
Quarto callouts for notes, tips, warnings:
```markdown
::: {.callout-tip title="Writing brand.yml with the help of an LLM"}
We know that writing YAML isn't everyone's cup of tea!
...
:::
```
Types: `note`, `tip`, `warning`, `caution`, `important`
## Embedded Media
### Videos
````markdown
::: column-page
```{=html}
```
:::
````
### Images with Attributes
```markdown
{.shadow}
```
Or with more attributes:
```markdown
{fig-alt="Detailed alt text" fig-align="center" width="100%"}
```
## Shinylive Examples
With the `shinylive` filter, you can embed live examples:
````markdown
```{shinylive-python}
#| standalone: true
#| components: [editor, viewer]
## file: app.py
from shiny.express import input, render, ui
# App code here
```
````
Or link to examples:
```markdown
We've added a [complete branded theming example](https://shinylive.io/py/examples/#branded-theming) to shinylive.io.
```
## Acknowledgements Section
Less consistent in Shiny posts. When present, variations include:
### Variation 1: Simple Thanks
```markdown
## Thanks!
Thank you for trying out the Shiny extension for VS Code!
If you find it helpful, please rate the extension on [the marketplace][Shiny extension].
```
### Variation 2: Multiple Package Releases
```markdown
## Release notes
**Big shout out to everyone involved!** 💙
We'd want to extend a huge thank you to everyone who contributed pull requests, bug reports and feature requests.
#### bslib [v0.7.0](https://rstudio.github.io/bslib/news/index.html#bslib-070)
[List of contributors]
#### shiny [v1.8.1](https://shiny.posit.co/r/reference/shiny/1.8.1/upgrade.html)
[List of contributors]
```
### Variation 3: Omitted
Some Shiny posts don't include acknowledgements, especially for announcements of tools rather than package releases.
### When Acknowledgements Are Included
Use similar format to Tidyverse:
```markdown
## Acknowledgements
We'd like to thank everyone who contributed to this release:
[@user1](https://github.com/user1), [@user2](https://github.com/user2), and [@user3](https://github.com/user3).
```
Or just reference the generator in code:
```markdown
```{r}
#| echo: false
#| eval: false
usethis::use_tidy_thanks("rstudio/bslib", from = "v0.6.1")
```
```
## CSS Customization
Shiny posts may include custom CSS in HTML blocks:
````markdown
```{=html}
```
````
## Column Layouts
Use Quarto's column classes for wider content:
```markdown
::: column-page
[Wide content here]
:::
::: column-body-outset
[Slightly wider content]
:::
```
## Footnotes
Use standard markdown footnotes:
```markdown
Text with a footnote[^footnote-key].
[^footnote-key]: This is the footnote text.
```
With `reference-location: document` or `section` in frontmatter to control placement.
## Links and References
Define link references at the top or bottom of the file:
```markdown
[brand.yml]: https://posit-dev.github.io/brand-yml
[quarto]: https://quarto.org
[shiny]: https://shiny.posit.co
```
Then use them inline:
```markdown
We're excited about [brand.yml] support!
```
## Multi-Language Support (R and Python)
The Shiny blog often covers packages released for both R and Python (e.g., shiny, shinychat). Unlike Tidyverse posts which are language-specific, Shiny posts should show examples in both languages using Quarto tabsets.
### Use Tabsets Consistently
Every code example should include both R and Python variants using Quarto tabsets:
```markdown
::: {.panel-tabset group="language"}
## R
```r
# R code here
```
## Python
```python
# Python code here
```
:::
```
**Guidelines:**
- Use `group="language"` to sync all language tabsets on the page
- Provide equivalent functionality in both languages
- Don't show R-only or Python-only examples unless the feature is language-specific
- Keep examples parallel—if the R example shows 5 lines, the Python example should be similar
### Installation Instructions
Always show installation for both languages at the start of the post:
```markdown
::: {.panel-tabset group="language"}
## R
```r
install.packages("packagename")
```
## Python
```bash
pip install packagename
```
:::
```
### Language-Specific Features
When features differ between languages, be explicit about the differences:
```markdown
::: {.panel-tabset group="language"}
## R
In R, use `tool_annotations()` to customize display:
```r
tool_annotations(title = "My Tool", icon = bsicons::bs_icon("star"))
```
## Python
In Python, use the `._display` attribute:
```python
my_tool._display = {"title": "My Tool", "icon": "star"}
```
:::
```
### Version Information
Package versions often differ between R and Python. Be explicit:
- "Available in shinychat for R (v0.3.0) and shinychat for Python (v0.2.0 or later)"
- Link to both language-specific documentation
- Include separate release notes links:
```markdown
You can see the full list of changes in the [R release notes](url) and [Python release notes](url).
```
### When to Use Multi-Language Tabsets
- **Always use** for packages that have both R and Python versions (shiny, shinychat, querychat, etc.)
- **Don't use** for Python-only packages (shinyswatch) or R-only packages
- **Don't use** for Tidyverse blog posts (which are built with hugodown/Hugo, not Quarto)
## Example Complete Frontmatter
### Python Package
```yaml
---
title: shinyswatch 0.7.0
description: &desc Customizable shinyswatch themes and an improved theme picker round out shinyswatch v0.7.0.
author: "Garrick Aden-Buie"
date: "2024-07-19"
image: feature.jpg
open-graph:
image: feature.jpg
description: *desc
twitter-card:
image: feature.png
description: *desc
filters:
- line-highlight
---
```
### R Package with Full Options
```yaml
---
title: "Shiny for R updates: Extended tasks, JavaScript errors, and many bslib improvements"
description: &desc |
An overview of recent Shiny for R updates, including extended tasks, JavaScript errors, and many bslib improvements.
author:
- Carson Sievert
date: "2024-03-27"
image: feature.png
open-graph:
image: feature.png
description: *desc
twitter-card:
image: feature.png
description: *desc
editor:
render-on-save: true
engine: knitr
filters:
- shinylive
freeze: true
format:
html:
code-link: true
anchor-sections: true
reference-location: section
code-annotations: hover
---
```
## Examples of Well-Formatted Posts
Reference these posts for formatting examples:
- [shinyswatch 0.7.0](https://shiny.posit.co/blog/posts/shinyswatch-0.7.0/)
- [Shiny Extension for VS Code 1.0.0](https://shiny.posit.co/blog/posts/shiny-vscode-1.0.0/)
- [Shiny for R 1.8.1](https://shiny.posit.co/blog/posts/shiny-r-1.8.1/)
- [Branded theming for Shiny for Python](https://shiny.posit.co/blog/posts/shiny-python-1.2-brand-yml/)