Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Export ui.card_body() #1128

Closed
gadenbuie opened this issue Feb 14, 2024 · 4 comments · Fixed by #1506
Closed

Export ui.card_body() #1128

gadenbuie opened this issue Feb 14, 2024 · 4 comments · Fixed by #1506

Comments

@gadenbuie
Copy link
Collaborator

Without making ui.card_body() public, it's impossible for app authors to give classes or attributes to the card body element that wraps the card body contents.

One way this plays out is in the differences between layout_sidebar() and a dynamically created sidebar layout. If you give ui.card() a ui.layout_sidebar() it doesn't wrap the sidebar layout into .card-body:

ui.card(
    ui.layout_sidebar(
        ui.sidebar("Left sidebar content", id="sidebar_left"),
        ui.output_text_verbatim("state_left"),
    )
)

but if you create the sidebar layout dynamically, you don't have access to the card body wrapper and have to live with the padding it adds to the card, unless you do something that feels very off-label to call ui._card.card_body()

ui.card(
    ui._card.card_body(
        ui.output_ui("sidebar_dynamic", fill=True, fillable=True), 
        class_="p-0"
    ),
),

Importantly, the class_ argument of ui.card() goes to the outer container, as do any tag attribute dictionaries.

@schloerke
Copy link
Collaborator

schloerke commented Feb 14, 2024

If we're going in on card_body()...

From

# TODO-barret-future; Update header to return CardHeader class. Same for footer. Then we
# can check `*args` for a CardHeader class and move it to the top. And footer to the
# bottom. Can throw error if multiple headers/footers are provided or could concatenate.

Can we have card_header() return a CardHeader class, and card_footer() return a CardFooter class? These two classes could inherit from CardItem. (CardBody could be added with no changes from parent class of CardItem).

Then we can hoist items of CardHeader to the top of a card and CardFooter to the bottom. Given we can single the value out, we could possibly throw if more than one of each type is found (or even combine their contents).

@gadenbuie
Copy link
Collaborator Author

Note that card_body() is currently available via shiny.experimental.ui.card_body() but the implementation lives in shiny.ui. Documentation would need to be updated as well.

@gadenbuie
Copy link
Collaborator Author

Another example noted in #1255:

This example also points out that ui.card() doesn't have a fillable argument, which could have been set to fillable=False in this case. Or ui.card_body() could be exported so that fillability can be disabled internally at the body level with ui.card(ui.card_body(..., fillable=False)).

@gadenbuie
Copy link
Collaborator Author

Another example. Because ui.card() doesn't have a fillable argument, it automatically chooses fillable=True for the implicit card body. In this context, empty ui.output_ui() elements still receive gap, adding additional space.

app_ui = ui.page_fillable(
    ui.layout_columns(
        ui.card(
            ui.output_ui("test_output"),
            ui.input_checkbox("hide_input", "Hide Input Below", True),
            ui.output_ui("test_output2"),
            ui.output_ui("test_output3"),
        ),
    ),
)

image

You can get around this by wrapping the elements in a ui.div(), which breaks fillability and restores regular margin spacing. But this is not ideal because it requires an understanding of the underlying CSS concepts that fillability was designed to avoid.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants