Skip to content

[FEATURE] Implement collapsible() Component for UI Layout #519

Open
@amrutha97

Description

@amrutha97

Goal
Add a collapsible() component to Preswald to support collapsible sections in the layout, enabling users to group related UI components inside expandable/collapsible containers.


📌 Motivation

Many data apps and dashboards built with Preswald involve long sequences of components—sliders, charts, tables, etc. Without layout control, the UI can become overwhelming. Grouping components within collapsible panels will:

  • Improve readability by reducing visible clutter
  • Allow logical grouping of related inputs and outputs
  • Enhance UX for interactive filtering and step-by-step exploration

This aligns with Preswald’s goal of creating structured, clean, and responsive data apps from simple Python scripts.


✅ Acceptance Criteria

  • Introduce collapsible() in preswald/preswald/interfaces/components.py
  • Render collapsible UI using ShadCN’s <Collapsible /> component from frontend/src/components/ui/collapsible.tsx
  • Frontend wrapper: /frontend/src/components/widgets/CollapsibleWidget.jsx
  • Register the component in DynamicComponents.jsx
  • Support optional parameters:
    • label: str (title/header of the collapsible section)
    • open: bool (default open/closed)
    • size: float (for layout control)
  • Ensure child components nested inside the collapsible container are properly rendered
  • Ensure compatibility with current backend → frontend component structure and UI state flow via WebSocket
  • Document usage in the SDK docs

🛠️ Implementation Plan

1. Backend – Add Component

preswald/interfaces/components.py

def collapsible(
    label: str,
    open: bool = True,
    size: float = 1.0,
) -> None:
    service = PreswaldService.get_instance()
    component_id = f"collapsible-{hashlib.md5(label.encode()).hexdigest()[:8]}"
    component = {
        "type": "collapsible",
        "id": component_id,
        "label": label,
        "open": open,
        "size": size,
    }
    service.append_component(component)

Register it in interfaces/__init__.py:

from .components import collapsible

2. Frontend – Add Widget

Create: frontend/src/components/widgets/CollapsibleWidget.jsx

import React from 'react';
import { Collapsible, CollapsibleTrigger, CollapsibleContent } from '@/components/ui/collapsible';
import { Card } from '@/components/ui/card';
import { ChevronDown } from 'lucide-react';

const CollapsibleWidget = ({ _label, _open = true, children }) => {
  const [isOpen, setIsOpen] = React.useState(_open);

  return (
    <Card className="mb-4 p-4 rounded-2xl shadow-md">
      <Collapsible open={isOpen} onOpenChange={setIsOpen}>
        <div className="flex justify-between items-center cursor-pointer" onClick={() => setIsOpen(!isOpen)}>
          <h2 className="font-semibold text-lg">{_label}</h2>
          <ChevronDown className={`transition-transform ${isOpen ? 'rotate-180' : ''}`} />
        </div>
        <CollapsibleContent>
          <div className="mt-4">{children}</div>
        </CollapsibleContent>
      </Collapsible>
    </Card>
  );
};

export default CollapsibleWidget;

3. DynamicComponents.jsx – Register

import CollapsibleWidget from '@/components/widgets/CollapsibleWidget';

case 'collapsible':
  return (
    <CollapsibleWidget
      {...commonProps}
      _label={component.label}
      _open={component.open}
    >
      {children}
    </CollapsibleWidget>
  );

✨ Optional: Nest children by pushing future components into a sublist within this container, depending on how Preswald manages layout/component trees internally.


🧪 Testing Plan

  • Add collapsible(label="Advanced Filters") above a group of sliders in examples/iris/hello.py
  • Confirm collapsible behavior toggles content visibility in browser
  • Confirm responsiveness and sizing rules
  • Run preswald run and validate via localhost:8501

🧾 Example Usage

from preswald import collapsible, slider, table, text

collapsible("Advanced Filters")
slider("Sepal Width", min_val=0, max_val=10, default=5.5)
slider("Sepal Length", min_val=0, max_val=10, default=4.5)

📚 Docs To Update

  • /docs/sdk/collapsible.mdx – with parameters, return type, image
  • /docs/layout/guide.mdx – mention collapsible as layout tool

📂 Related Files

  • frontend/src/components/ui/collapsible.tsx
  • frontend/src/components/widgets
  • preswald/interfaces/components.py
  • DynamicComponents.jsx

🧩 Additional Notes

  • collapsible() should not return a value — it's purely structural
  • Consider nesting logic if children grouping becomes supported
  • Follow style consistency (rounded-2xl, card padding, hover icons)

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions