port-from-bslib

2
0
Source

Comprehensive guide for porting UI components from R's bslib package to py-shiny. Use this skill when: (1) User asks to "port this feature" or "port a component" and mentions bslib or links to a bslib PR (e.g., github.com/rstudio/bslib/pull/...), (2) Porting a new component from bslib to py-shiny, (3) Adding a new input, output, or UI component that exists in bslib, (4) Implementing feature parity with bslib, (5) Working on bslib-related features or components. Covers the complete workflow including understanding source implementation, creating Python equivalents, vendoring assets (SCSS, CSS, JavaScript), creating tests, documentation, and all necessary project files.

Install

mkdir -p .claude/skills/port-from-bslib && curl -L -o skill.zip "https://mcp.directory/api/skills/download/3353" && unzip -o skill.zip -d .claude/skills/port-from-bslib && rm skill.zip

Installs to .claude/skills/port-from-bslib

About this skill

Porting Components from bslib to py-shiny

This guide explains how to port new UI components from the R bslib package to py-shiny. It assumes you're an experienced developer familiar with Python, R, and JavaScript/TypeScript, but may be new to the specifics of these repositories.

Background

The bslib R package serves as the primary development location for new Bootstrap 5 components in the Shiny ecosystem. Components developed in bslib are then ported to py-shiny to maintain feature parity between Shiny for R and Shiny for Python.

Key relationship: bslib provides both the R implementation and the compiled JavaScript/CSS assets that py-shiny vendors and uses directly.

Overview of the Porting Process

The porting process involves three main phases:

  1. Understanding the source - Study the bslib implementation (R, TypeScript, SCSS)
  2. Implementing the port - Create Python equivalents and add client-side bindings
  3. Testing and documentation - Ensure correctness with unit and end-to-end tests

Phase 1: Understanding the Source Implementation

Step 1.1: Locate the bslib PR

Find the bslib PR that introduced the feature. The py-shiny PR description should reference it (e.g., Related https://github.com/rstudio/bslib/pull/...).

Checklist:

  • Located the bslib PR
  • Reviewed the PR description and any design discussions

Step 1.2: Identify the core source files

In the bslib PR, locate these key files:

  1. R implementation: R/[feature-name].R - The main component function(s)
  2. TypeScript bindings: srcts/src/components/[featureName].ts - Client-side behavior
  3. SCSS styles: inst/components/scss/[feature_name].scss - Component styles
  4. Unit tests: tests/testthat/test-[feature-name].R - R unit tests

Note: Generated files (compiled JS/CSS, documentation) can be ignored - focus on source files.

Checklist:

  • Found the R implementation file(s)
  • Found the TypeScript source file(s)
  • Found the SCSS source file
  • Found the unit test file(s)
  • Reviewed how TypeScript is registered in srcts/src/components/index.ts

Step 1.3: Understand the component structure

Study the bslib implementation to understand:

  1. API design: Function signature, parameters, defaults
  2. HTML structure: The DOM elements created by the R function
  3. Client-side behavior: How the TypeScript binding handles interactions
  4. Shiny communication: How the component sends/receives values from the server
  5. Dependencies: What other components or utilities it relies on

Key patterns to note:

  • Is the component an input binding? If so, how does the binding register (typically via a CSS class)?
  • What markup structure does it generate on the server side?
  • How does the component integrate with Bootstrap classes?
  • How are configuration options passed from R to JavaScript -- data attributes, embedded JSON, etc.?
  • How does the component receive data from the server -- via sendInputMessage() or sendCustomMessage()?
  • How does the component receive data from the client -- via receiveMessage() or small inputs set with Shiny.setInputValue()?

Checklist:

  • Documented the component's API surface
  • Understood the HTML structure and CSS classes
  • Identified client-side event handlers and state management
  • Noted any dependencies on other components

Phase 2: Implementing the Port

Step 2.1: Create the Python implementation

Create a new file in shiny/ui/ for the component implementation.

File naming: Use snake_case matching the R function name:

  • R: input_submit_textarea() → Python: _input_submit_textarea.py

Implementation notes:

  • Translate R's htmltools to Python's htmltools
  • Use @add_example() decorator for documentation examples (examples are created in a later step)
  • Follow existing patterns for parameter validation
  • Use resolve_id() for module namespace support
  • Use restore_input() for bookmarking support
  • Include both the main component function and any update_*() functions

Common translations:

  • R tags$div() → Python div() or tags.div()
  • R !!!args (splicing) → Python *args+**kwargs
  • R NULL → Python None
  • R lists → Python dicts or lists as appropriate
  • R paste0() → Python f-strings or .format()

Checklist:

  • Created shiny/ui/_[component_name].py
  • Implemented the main component function with full docstring
  • Implemented any update_*() functions
  • Added parameter validation
  • Added support for modules (resolve_id)
  • Added support for bookmarking (restore_input)
  • Used components_dependencies() for client-side deps

Step 2.2: Export the new functions

Update shiny/ui/__init__.py to export the new component:

from ._input_submit_textarea import input_submit_textarea, update_submit_textarea

__all__ = (
    # ... existing exports ...
    "input_submit_textarea",
    "update_submit_textarea",
)

If the component is suitable for express mode, also export from shiny/express/ui/__init__.py.

Checklist:

  • Added imports to shiny/ui/__init__.py
  • Added to __all__ tuple in shiny/ui/__init__.py
  • (If applicable) Exported from shiny/express/ui/__init__.py

Step 2.3: Vendor assets from bslib

The TypeScript in bslib is compiled to JavaScript and bundled, and SCSS is compiled to CSS. Py-shiny vendors these compiled assets along with the SCSS source files from bslib.

Process:

  1. Ensure bslib PR is merged and the feature is in the branch referenced in scripts/_pkg-sources.R (usually @main)
  2. If vendoring from a non-default branch or specific commit, update scripts/_pkg-sources.R temporarily
  3. Run make upgrade-html-deps to vendor the latest assets from bslib, shiny, sass, and htmltools

What make upgrade-html-deps does:

  • Copies SCSS source files from bslib to shiny/www/shared/sass/bslib/components/scss/
  • Updates all theme preset _04_rules.scss files to import the new SCSS
  • Compiles SCSS to CSS for all themes
  • Vendors compiled JavaScript bundles (components.min.js, etc.)
  • Updates other shared assets from upstream packages

Files updated by this process (examples):

  • shiny/www/shared/sass/bslib/components/scss/[feature_name].scss (SCSS source)
  • shiny/www/shared/sass/preset/*/04_rules.scss (27 theme preset files with new imports)
  • shiny/www/shared/bslib/components/components.min.js (compiled JavaScript)
  • shiny/www/shared/bslib/components/components.min.js.map (source map)
  • shiny/www/shared/bslib/components/components.css (compiled CSS)
  • Other theme-specific CSS files

Note: This is a manual process that's not part of CI. The vendored files are committed to the repository.

Checklist:

  • Verified bslib PR is merged (or adjusted scripts/_pkg-sources.R if needed)
  • Ran make upgrade-html-deps
  • Reviewed changes to vendored files (SCSS, CSS, JS)
  • Verified new SCSS imports in theme preset files
  • Restored scripts/_pkg-sources.R if temporarily modified

Step 2.4: Create API examples

Create example applications demonstrating the component's usage.

Location: shiny/api-examples/[component_name]/

Files to create:

  • app-core.py - Core mode example
  • app-express.py - Express mode example (if applicable)

Example structure:

# app-express.py
from shiny.express import input, render, ui

ui.input_submit_textarea("text", placeholder="Enter some input...")

@render.text
def value():
    if "text" in input:
        return f"You entered: {input.text()}"
    else:
        return "Submit some input to see it here."

Best practices:

  • Keep examples simple and focused
  • Demonstrate the primary use case
  • Show server-side value handling patterns
  • Include any important parameter variations
  • Re-use examples from bslib where possible
  • Always include an Express version unless there's a strong reason not to
  • A human reviewer should test the examples locally

Checklist:

  • Created shiny/api-examples/[component]/app-core.py
  • Created shiny/api-examples/[component]/app-express.py (unless not warranted)
  • Tested examples locally

Step 2.5: Add Playwright controller (if input component)

If the component is an input component, create a Playwright controller for end-to-end testing.

Location: shiny/playwright/controller/_input_fields.py (or create new file if needed)

Implementation:

  1. Create a new class inheriting from appropriate mixins
  2. Implement required methods: __init__, set, interaction methods
  3. Add expectation methods for testing (e.g., expect_value, expect_placeholder)
  4. Follow existing patterns for locator initialization

Example pattern:

class InputSubmitTextarea(
    _SetTextM,
    WidthContainerStyleM,
    _ExpectTextInputValueM,
    _ExpectPlaceholderAttrM,
    _ExpectRowsAttrM,
    UiWithLabel,
):
    """Controller for :func:`shiny.ui.input_submit_textarea`."""

    loc_button: Locator

    def __init__(self, page: Page, id: str) -> None:
        super().__init__(
            page,
            id=id,
            loc=f"textarea#{id}.form-control",
        )
        self.loc_button = self.loc_container.locator(".bslib-submit-textarea-btn")

    def set(self, value: str, *, submit: bool = False, timeout: Timeout = None) -> None:
        # Implementation
        pass

Don't forget to export: Update shiny/playwright/controller/__init__.py to export the new controller class.

Checklist:

  • Created Playwright controller class
  • Implemented core interaction methods
  • Implemented expectation methods for testing
  • Exported from shiny/playwright/controller/__init__.py
  • Added to __all__ in the same file

Phase 3: Testing and Documentation

Step 3.1: Port unit tests from bslib

Port the relevant unit tests from bslib's testthat tests to pytest.

Translation patterns:


Content truncated.

positron-qa-verify

posit-dev

Generates clear, actionable verification guides for QA testing of Positron bug fixes and features

00

positron-issue-creator

posit-dev

This skill should be used when drafting GitHub issues for the Positron repository. It provides workflows for searching duplicates, selecting appropriate labels, gathering complete context through questioning, and writing terse, fluff-free issues that precisely describe what is needed or wrong. The skill prepares issues for manual submission by the user. Use this skill when the user asks to draft or prepare an issue for Positron.

10

positron-notebooks

posit-dev

This skill should be used when developing, debugging, or maintaining Positron Notebooks - the React-based feature-flagged notebook editor. Load this skill when tasks involve notebook cells, execution, selection state, context keys, or notebook editor features.

00

positron-intake-rotation

posit-dev

This skill should be used when handling issue intake rotation duties for the Positron repository. It provides workflows for reviewing and organizing new issues, responding to discussions, handling support tickets, and searching for related content. Use this skill when on intake rotation duty, when helping someone with intake tasks, or when learning the intake rotation process.

80

positron-e2e-tests

posit-dev

This skill should be used when writing, debugging, or maintaining Playwright e2e tests for Positron. Load this skill when creating new test files, adding test cases, fixing flaky tests, or understanding the test infrastructure.

70

positron-pr-helper

posit-dev

Generates well-structured PR bodies with dynamically fetched e2e test tags

30

You might also like

flutter-development

aj-geddes

Build beautiful cross-platform mobile apps with Flutter and Dart. Covers widgets, state management with Provider/BLoC, navigation, API integration, and material design.

643969

drawio-diagrams-enhanced

jgtolentino

Create professional draw.io (diagrams.net) diagrams in XML format (.drawio files) with integrated PMP/PMBOK methodologies, extensive visual asset libraries, and industry-standard professional templates. Use this skill when users ask to create flowcharts, swimlane diagrams, cross-functional flowcharts, org charts, network diagrams, UML diagrams, BPMN, project management diagrams (WBS, Gantt, PERT, RACI), risk matrices, stakeholder maps, or any other visual diagram in draw.io format. This skill includes access to custom shape libraries for icons, clipart, and professional symbols.

591705

ui-ux-pro-max

nextlevelbuilder

"UI/UX design intelligence. 50 styles, 21 palettes, 50 font pairings, 20 charts, 8 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, mobile app, .html, .tsx, .vue, .svelte. Elements: button, modal, navbar, sidebar, card, table, form, chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, flat design. Topics: color palette, accessibility, animation, layout, typography, font pairing, spacing, hover, shadow, gradient."

318398

godot

bfollington

This skill should be used when working on Godot Engine projects. It provides specialized knowledge of Godot's file formats (.gd, .tscn, .tres), architecture patterns (component-based, signal-driven, resource-based), common pitfalls, validation tools, code templates, and CLI workflows. The `godot` command is available for running the game, validating scripts, importing resources, and exporting builds. Use this skill for tasks involving Godot game development, debugging scene/resource files, implementing game systems, or creating new Godot components.

339397

nano-banana-pro

garg-aayush

Generate and edit images using Google's Nano Banana Pro (Gemini 3 Pro Image) API. Use when the user asks to generate, create, edit, modify, change, alter, or update images. Also use when user references an existing image file and asks to modify it in any way (e.g., "modify this image", "change the background", "replace X with Y"). Supports both text-to-image generation and image-to-image editing with configurable resolution (1K default, 2K, or 4K for high resolution). DO NOT read the image file first - use this skill directly with the --input-image parameter.

451339

fastapi-templates

wshobson

Create production-ready FastAPI projects with async patterns, dependency injection, and comprehensive error handling. Use when building new FastAPI applications or setting up backend API projects.

304231

Stay ahead of the MCP ecosystem

Get weekly updates on new skills and servers.