Skip to content

Issues with positional arguments and shiny.express.ui components #947

@cpsievert

Description

@cpsievert

Problem

I can see two issues with how shiny.express.ui handles positional arguments:

  1. Many functions don't pass along positional arguments (i.e., they have * instead of *args in their signature). This means you can't currently use things like ui.card() the "functional" way:
from shiny.express import ui

ui.card("foo", "bar")
TypeError: card() takes 0 positional arguments but 2 were given
  1. Some functions have named positional arguments, which forces those arguments to be specified when used the "context-manager" way. For example, since value_box() has title/value as named positional args, usage must look like this:
with value_box("Title", "Value"):
    pass

...which is unfortunate, especially when you want to a dynamically rendered value.

Proposal

I think we can solve both issues by taking inspiration from how card_header() currently works. That is, if the underlying UI function takes any positional arguments, we always start the express function with *args and pass those args to the underlying UI function

def card_header(
*args: TagChild | TagAttrs,
container: TagFunction = ui.tags.div,
**kwargs: TagAttrValue,
) -> RecallContextManager[CardItem]:
"""
Context manager for a card header container
This function wraps :func:`~shiny.ui.card_header`.
A general container for the "header" of a :func:`~shiny.ui.card`. This component is designed
to be provided as a direct child to :func:`~shiny.ui.card`.
The header has a different background color and border than the rest of the card.
Parameters
----------
*args
Contents to the header container. Or tag attributes that are supplied to the
resolved :class:`~htmltools.Tag` object.
container
Method for the returned Tag object. Defaults to :func:`~shiny.ui.tags.div`.
**kwargs
Additional HTML attributes for the returned Tag.
"""
return RecallContextManager(
ui.card_header,
args=args,
kwargs=dict(
container=container,
**kwargs,
),
)

This does lead to the question of whether functions like nav_panel() should be (title, *args, **kwargs) or (*args, **kwargs), but it seems pretty sensible to me (for consistency sake) that we go in the latter direction.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions