Skip to main content
Layout components provide the structural foundation for your Loopar applications. They handle responsive design, spacing, alignment, and visual organization.

Container

The container component is the main wrapper for page content. It provides background styling and houses droppable areas.
packages/loopar/src/components/container.jsx
export default function Container(props){
  const { designerMode, designerModeType } = useDesigner();
  const newProps = {...props};
  delete newProps.style;

  return (
    <div   
      {...props}
      className={!designerMode || designerModeType == "preview" ? "min-h-page bg-cover bg-center bg-fixed" : ""}
    >
      <Droppable {...newProps}/>
    </div>
  );
}

Usage

{
  "element": "container",
  "data": {
    "key": "main-container",
    "background_image": "/path/to/image.jpg",
    "background_color": "rgba(0,0,0,0.1)"
  },
  "elements": []
}
data.background_image
string
Background image URL
data.background_color
string
Background color (supports rgba)

Row

The row component creates responsive grid layouts with configurable columns. It uses CSS Grid for dynamic column sizing.
packages/loopar/src/components/row.jsx
export default function Row(props) {
  const { setElements, set } = ComponentDefaults(props);
  const data = props.data;
  const [layout, setLayout] = useState(loopar.utils.JSONparse(data.layout, [50, 50]));
  const [cols, setCols] = useState(props.elements || []);
  
  return (
    <RowContextProvider
      colPadding={config.col_padding}
      colMargin={config.col_margin}
      spacing={_spacing}
    >
      <div className={cn("flex flex-col", rowHeight)}>
        <Droppable
          {...props}
          elements={cols}
          className={cn(
            "@container",
            "grid grid-cols-1 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-2 w-full",
            "grid-container dynamic box-border",
            rowHeight,
            data.class,
          )}
          style={{
            "--gap-solver": `${gapSolver}rem`,
            "--column-layout": `calc(${layoutAdjust.join("% - var(--gap-solver)) calc(")}% - var(--gap-solver))`,
            gap: `${_spacing}rem`,
            ...props.style,
          }}
        />
      </div>
    </RowContextProvider>
  );
}

Layout Options

{
  "element": "row",
  "data": {
    "layout": "[50, 50]",
    "spacing": 2
  }
}

Properties

data.layout
array
required
Array of column widths (percentages). Example: [50, 50] for equal columns
data.spacing
number
default:1
Gap between columns in rem (0-6)
data.col_padding
string
default:"p-0"
Padding for all columns. Options: p-0 through p-9
data.horizontal_alignment
string
default:"left"
Horizontal alignment: left, center, right
data.vertical_alignment
string
default:"top"
Vertical alignment: top, center, bottom
data.row_height
string
default:"auto"
Row height: auto, 100 (100vh), 75, 50, 25
data.full_height
boolean
default:false
Override height to 100vh (full screen)

Meta Fields

packages/loopar/src/components/row.jsx
Row.metaFields = () => {
  return [
    {
      group: "layout",
      elements: {
        layout: {
          element: SELECT,
          data: {
            label: "Columns",
            options: gridLayouts.map(l => `[${l}]`),
            default_value: "[50, 50]",
          },
        },
        spacing: {
          element: SELECT,
          data: {
            label: "Gap",
            options: [0, 1, 2, 3, 4, 5, 6],
            default_value: 1,
            description: "Spacing between columns in rem.",
          },
        },
      },
    },
  ];
};

Col

The col component represents a column within a row. It automatically adjusts based on the row’s layout.
packages/loopar/src/components/col.jsx
export default function Col(props) {
  const { designerMode, designing } = useDesigner();
  const { colPadding } = useRowContext();
  const data = props.data || {};

  const className = cn(
    (!designerMode || !designing) && colPadding, 
    props.className, 
    'h-full', 
    data?.class
  );
  
  return (
    <Droppable
      {...props}
      className={className}
    />
  );
}

Col.dontHaveMetaElements = ["label", "text"];
Col.droppable = true;

Usage

{
  "element": "col",
  "data": {
    "key": "col-1",
    "class": "bg-gray-100"
  },
  "elements": [
    // Child components
  ]
}

Card

The card component creates a material design card with header, content, and footer sections.
packages/loopar/src/components/card.jsx
export default function Card(props) {
  const data = props.data || {};

  return (
    <CardHover {...loopar.utils.renderizableProps(props)}>
      <CardHeader>
        <CardTitle>{data.label}</CardTitle>
        {data.description && <CardDescription>{data.description}</CardDescription>}
      </CardHeader>
      <Droppable
        Component={CardContent}
        {...props}
      />
      {props.footer && (
        <CardFooter className="flex justify-between">
          {props.footer}
        </CardFooter>
      )}
    </CardHover>
  )
}

function CardHover(props){
  return (
    <CardComponent 
      className={cn(props.className, "transition-all hover:shadow-lg h-full")}
    >
      {props.children}
    </CardComponent>
  )
}

Properties

data.label
string
required
Card title
data.description
string
Card description (subtitle)
Footer content

Example

{
  "element": "card",
  "data": {
    "label": "User Profile",
    "description": "Manage your account settings",
    "key": "profile-card"
  },
  "elements": [
    {
      "element": "input",
      "data": {
        "label": "Username",
        "name": "username"
      }
    }
  ]
}
The banner component creates hero sections with background images, animations, and overlays.
packages/loopar/src/components/banner.jsx
function Banner() {
  const {props} = usePreassembledContext()
  const data = props.data || {};

  const alignment = {
    center: "justify-center items-center",
    start: "justify-start items-start",
    end: "justify-end items-end",
  }[data?.alling || "center"];
  
  return (
    <div className={cn(props.className.split("transition-all")[0], "p-0 relative min-h-100")}>
      <Cover
        className="h-full w-full absolute inset-0 z-0"
        style={props.style}
        animation={data.animation}
      />
      <Content  
        elements={props.elements}
        data={{key: data.key}} 
        className={cn(alignment, data.class)}
        isActive={isActive}
      />
    </div>
  )
}

Properties

data.alling
string
default:"center"
Content alignment: center, start, end
data.animation
string
Animation type for entrance effect
data.background_image
string
Banner background image URL
data.color_overlay
string
Overlay color (rgba format)

Example

{
  "element": "banner",
  "data": {
    "key": "hero-banner",
    "label": "Welcome to Loopar",
    "text": "Build applications faster",
    "alling": "center",
    "background_image": "https://example.com/hero.jpg",
    "color_overlay": "rgba(0,0,0,0.5)"
  }
}

Tabs

The tabs component creates a tabbed interface with dynamic tab management.
packages/loopar/src/components/tabs.jsx
export default function MetaTabs(props){
  const {data, setElements} = ComponentDefaults(props);
  
  return (
    <div className="p-2 my-3 border border-separate" id={data.id}>
      {data.label && <h4 className="p-2">{data.label}</h4>}
      <TabFn
        id={data.id || data.name || data.key}
        data={data}
        elementsDict={elementsDict}
        setElements={setElements}
        canCustomize={props.canCustomize}
      />
    </div>
  )
}

MetaTabs.requires = ["tab"]

Properties

data.label
string
Tabs container label
canCustomize
boolean
default:true
Allow adding/removing tabs in designer

Example

{
  "element": "tabs",
  "data": {
    "key": "settings-tabs",
    "label": "Settings"
  },
  "elements": [
    {
      "element": "tab",
      "data": {
        "key": "general",
        "label": "General"
      },
      "elements": []
    },
    {
      "element": "tab",
      "data": {
        "key": "security",
        "label": "Security"
      },
      "elements": []
    }
  ]
}

Section

The section component groups related content with optional styling.

Usage

{
  "element": "section",
  "data": {
    "key": "about-section",
    "class": "py-10 bg-white"
  },
  "elements": []
}

Panel

The panel component creates collapsible content areas.

Usage

{
  "element": "panel",
  "data": {
    "key": "details-panel",
    "label": "Advanced Options",
    "collapsed": false
  },
  "elements": []
}

Component Defaults

All layout components use the ComponentDefaults helper:
packages/loopar/src/components/base/ComponentDefaults.jsx
export function ComponentDefaults(props) {
  const data = props.data || {};
  const {updateElement, updateElements, designerMode} = useDesigner();

  const set = (key, value) => {
    if (!designerMode) return;
    const newData = {...data};
    if (typeof key == "object") {
      Object.keys(key).forEach((k) => {
        newData[k] = key[k];
      });
    } else {
      newData[key] = value;
    }

    setTimeout(() => {
      updateElement(data.key, JSON.parse(JSON.stringify(newData), true, false, true))
    }, 100);
  }

  return {
    getSrc,
    getTextSize,
    getTextAlign,
    set,
    setElements,
    getSize,
    data
  }
}

Next Steps

Form Components

Learn about inputs, selects, and form elements

Data Display

Display data with tables and dialogs

Build docs developers (and LLMs) love