Module
If our Box
is an atom, the Module
component is an extension of a Box
which you might consider a molecule. Module
standardizes common patterns used across the platform to ensure consistency. If the design calls for a Box
with a header, actions, content, and/or footer, you can use a Module
to provide that structure easily and consistently.
Why this approach?
Composability. Breaking up what might seem like a single concept of a Module
into multiple components like this helps us to maintain AND test them more easily.
Module
, ModuleHeader
, ModuleContent
, ModuleFooter
can be separate components. Not every Module
implemented needs to use all of them. Some modules don't have headers or footers, etc. This is a very powerful composability pattern used by popular UI component libraries to improve testability and maintainability while giving end users the a lot of flexibility in the cleanest possible way. The resulting usage becomes much clearer, as opposed to a single component with many props, slots and/or schemas, you've got a very declarative composition of components.
It also provides the consumer developers & applications the flexibility they need to build out screens the way they want to without having a single massive component made up of many components, which we need to control through schemas, or passing nested props, or having tons of slots. All of which creates complexities in testing and maintaining a component without breaking things.
Detailed notes & conceptual designs: https://whimsical.com/module-component-Azer1UzmQPSXZowztyt1bn
When to use Module
components
Don't use Module's as a replacement for Card
's! Card's are containers for content representing a single entity. e.g. a product, credit profile, or licence, etc. Modules are meant to be used to give a typical Box
some structure, allowing us to have consistent designs with minimal code, making it easier for FE devs to build screens rapidly.
When a design calls for a simple Box
but also has a header title & actions and some footer links, that's a good indication that you should using a Module
. The actual content is not particularly important for Modules.
Basic Usage
Order Details
Render anything you want in a ModuleContent!
- Order no
- #123123
- Quantity
- 3
- Category
- Flower
<Module>
<ModuleHeader>Order Details</ModuleHeader>
<ModuleContent>
<p>Render anything you want in a ModuleContent!</p>
<DescriptionList>
<DescriptionListGroup>
<DescriptionListTerm>Order no</DescriptionListTerm>
<DescriptionListDetail>#123123</DescriptionListDetail>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>Quantity</DescriptionListTerm>
<DescriptionListDetail>3</DescriptionListDetail>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>Category</DescriptionListTerm>
<DescriptionListDetail>Flower</DescriptionListDetail>
</DescriptionListGroup>
</DescriptionList>
</ModuleContent>
</Module>
Header actions
slot
You can add whatever you'd like in the actions
slot. The primary use case is have user CTA's like context menus, icons or icon buttons.
User Permissions
Select companies the user
Render anything you want in a ModuleContent!
- Order no
- #123123
- Quantity
- 3
- Category
- Flower
<Module>
<ModuleHeader title="User Permissions" description="Select companies the user should have access to and select their role.">
<template #actions>
<Button primary>Add Companies</Button>
</template>
</ModuleHeader>
<ModuleContent>
<p>Render anything you want in a ModuleContent!</p>
<DescriptionList>
<DescriptionListGroup>
<DescriptionListTerm>Order no</DescriptionListTerm>
<DescriptionListDetail>#123123</DescriptionListDetail>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>Quantity</DescriptionListTerm>
<DescriptionListDetail>3</DescriptionListDetail>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>Category</DescriptionListTerm>
<DescriptionListDetail>Flower</DescriptionListDetail>
</DescriptionListGroup>
</DescriptionList>
</ModuleContent>
</Module>
Buyer
The Green Store
15308 E 8 Mile RdDetroit, MI 48205
Phone: (555) 555-5555
Email: thegreenstore@gmail.com
Reference ID: 03948487
Seller
The Blue Store
97548 E 8 Mile RdDetroit, MI 48205
Phone: (123) 555-9876
Email: thebluestore@gmail.com
Reference ID: 87654338
<section class="tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-gutter">
<Module>
<ModuleHeader title="Buyer" size="large">
<template #actions>
<Icon name="edit" @click="alert('Edit!')" />
</template>
</ModuleHeader>
<ModuleContent>
<h3 class="tw-mb-6">The Green Store</h3>
<address class="tw-mb-2">
15308 E 8 Mile Rd<br>
Detroit, MI 48205
</address>
<p class="tw-mb-2"><strong>Phone:</strong> (555) 555-5555</p>
<p class="tw-mb-3"><strong>Email:</strong> thegreenstore@gmail.com</p>
<p><strong>Reference ID:</strong> 03948487</p>
</ModuleContent>
<ModuleFooter>
<a href="#" @click.prevent="">View Licenses</a>
</ModuleFooter>
</Module>
<Module>
<ModuleHeader title="Seller" size="large">
<template #actions>
<Icon name="edit" @click="alert('Edit!')" />
</template>
</ModuleHeader>
<ModuleContent>
<h3 class="tw-mb-6">The Blue Store</h3>
<address class="tw-mb-2">
97548 E 8 Mile Rd<br>
Detroit, MI 48205
</address>
<p class="tw-mb-2"><strong>Phone:</strong> (123) 555-9876</p>
<p class="tw-mb-3"><strong>Email:</strong> thebluestore@gmail.com</p>
<p><strong>Reference ID:</strong> 87654338</p>
</ModuleContent>
<ModuleFooter>
<a href="#" @click.prevent="">View Licenses</a>
</ModuleFooter>
</Module>
</section>
Header underline
option
User Permissions
Select companies the user should have access to and select their role.
Render anything you want in a ModuleContent!
- Order no
- #123123
- Quantity
- 3
- Category
- Flower
<Module>
<ModuleHeader title="User Permissions" description="Select companies the user should have access to and select their role." underline>
<template #actions>
<Button primary>Add Companies</Button>
</template>
</ModuleHeader>
<ModuleContent>
<p>Render anything you want in a ModuleContent!</p>
<DescriptionList>
<DescriptionListGroup>
<DescriptionListTerm>Order no</DescriptionListTerm>
<DescriptionListDetail>#123123</DescriptionListDetail>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>Quantity</DescriptionListTerm>
<DescriptionListDetail>3</DescriptionListDetail>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>Category</DescriptionListTerm>
<DescriptionListDetail>Flower</DescriptionListDetail>
</DescriptionListGroup>
</DescriptionList>
</ModuleContent>
</Module>
Buyer
The Green Store
15308 E 8 Mile RdDetroit, MI 48205
Phone: (555) 555-5555
Email: thegreenstore@gmail.com
Reference ID: 03948487
Seller
The Blue Store
97548 E 8 Mile RdDetroit, MI 48205
Phone: (123) 555-9876
Email: thebluestore@gmail.com
Reference ID: 87654338
<section class="tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-gutter">
<Module>
<ModuleHeader title="Buyer" size="large" underline>
<template #actions>
<Icon name="edit" @click="alert('Edit!')" />
</template>
</ModuleHeader>
<ModuleContent>
<h3 class="tw-mb-6">The Green Store</h3>
<address class="tw-mb-2">
15308 E 8 Mile Rd<br>
Detroit, MI 48205
</address>
<p class="tw-mb-2"><strong>Phone:</strong> (555) 555-5555</p>
<p class="tw-mb-3"><strong>Email:</strong> thegreenstore@gmail.com</p>
<p><strong>Reference ID:</strong> 03948487</p>
</ModuleContent>
<ModuleFooter>
<a href="#" @click.prevent="">View Licenses</a>
</ModuleFooter>
</Module>
<Module>
<ModuleHeader title="Seller" size="large" underline>
<template #actions>
<Icon name="edit" @click="alert('Edit!')" />
</template>
</ModuleHeader>
<ModuleContent>
<h3 class="tw-mb-6">The Blue Store</h3>
<address class="tw-mb-2">
97548 E 8 Mile Rd<br>
Detroit, MI 48205
</address>
<p class="tw-mb-2"><strong>Phone:</strong> (123) 555-9876</p>
<p class="tw-mb-3"><strong>Email:</strong> thebluestore@gmail.com</p>
<p><strong>Reference ID:</strong> 87654338</p>
</ModuleContent>
<ModuleFooter>
<a href="#" @click.prevent="">View Licenses</a>
</ModuleFooter>
</Module>
</section>
Header Media
Use the media
slot for rendering an Illustration alongside the title.
Payment preferences
View and manage your company's payment preferences
Render anything you want in a ModuleContent!
- Order no
- #123123
- Quantity
- 3
- Category
- Flower
<Module>
<ModuleHeader
title="Payment preferences"
description="View and manage your company's payment preferences"
size="large"
>
<template #media>
<Illustration name="money" :size="65" />
</template>
</ModuleHeader>
<ModuleContent>
<p>Render anything you want in a ModuleContent!</p>
<DescriptionList>
<DescriptionListGroup>
<DescriptionListTerm>Order no</DescriptionListTerm>
<DescriptionListDetail>#123123</DescriptionListDetail>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>Quantity</DescriptionListTerm>
<DescriptionListDetail>3</DescriptionListDetail>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>Category</DescriptionListTerm>
<DescriptionListDetail>Flower</DescriptionListDetail>
</DescriptionListGroup>
</DescriptionList>
</ModuleContent>
</Module>
Content "top" slots
Render anything you want in a ModuleContent!
- Order no
- #123123
- Quantity
- 3
- Category
- Flower
<Module>
<ModuleContent>
<template #top-left><IconLabel color="ice" icon="circle-status">Inactive</IconLabel></template>
<template #top-right>
<RadioGroup v-model="someRadio" name="someRadio" variant="button">
<Radio id="active" label="Active" value="1" />
<Radio id="inactive" label="Inactive" value="2" />
</RadioGroup>
</template>
<p>Render anything you want in a ModuleContent!</p>
<DescriptionList>
<DescriptionListGroup>
<DescriptionListTerm>Order no</DescriptionListTerm>
<DescriptionListDetail>#123123</DescriptionListDetail>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>Quantity</DescriptionListTerm>
<DescriptionListDetail>3</DescriptionListDetail>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>Category</DescriptionListTerm>
<DescriptionListDetail>Flower</DescriptionListDetail>
</DescriptionListGroup>
</DescriptionList>
</ModuleContent>
</Module>
Having a lot of content will cause the top slots to wrap:
Render anything you want in a ModuleContent!
- Order no
- #123123
- Quantity
- 3
- Category
- Flower
<Module>
<ModuleContent>
<template #top-left>
Left Slot! A lot of content here will cause the slots to wrap! Try shrinking the canvas.
</template>
<template #top-right>
<Button class="tw-mr-6" secondary>Right Slot Secondary button</Button>
<Button>Right Slot!</Button>
</template>
<p>Render anything you want in a ModuleContent!</p>
<DescriptionList>
<DescriptionListGroup>
<DescriptionListTerm>Order no</DescriptionListTerm>
<DescriptionListDetail>#123123</DescriptionListDetail>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>Quantity</DescriptionListTerm>
<DescriptionListDetail>3</DescriptionListDetail>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>Category</DescriptionListTerm>
<DescriptionListDetail>Flower</DescriptionListDetail>
</DescriptionListGroup>
</DescriptionList>
</ModuleContent>
</Module>
Disable gutters
Order Details
You can render anything you want in a Module
, but they are typically meant to be used with ModuleContent
or other sibling components.
If all you need is the elevated surface styling, use Box
instead.
<Module disable-gutters>
<ModuleHeader>Order Details</ModuleHeader>
<ModuleContent>
<p>You can render anything you want in a <code>Module</code>, but they are typically meant to be used with <code>ModuleContent</code> or other sibling components.</p>
<p>If all you need is the elevated surface styling, use <code>Box</code> instead.</p>
</ModuleContent>
</Module>
Disable padding
Order Details
You can render anything you want in a Module
, but they are typically meant to be used with ModuleContent
or other sibling components.
If all you need is the elevated surface styling, use Box
instead.
<Module disable-padding>
<ModuleHeader>Order Details</ModuleHeader>
<ModuleContent>
<p>You can render anything you want in a <code>Module</code>, but they are typically meant to be used with <code>ModuleContent</code> or other sibling components.</p>
<p>If all you need is the elevated surface styling, use <code>Box</code> instead.</p>
</ModuleContent>
</Module>
Grid display
When displaying modules in a grid they will automatically match heights and the content areas will flex so that the footers all line up with each other.
Module header
Module content will fill the remaining space of a module. We've added a border to illustrate this.
Module header
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Module header
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
<section class="tw-grid tw-grid-cols-12 tw-gap-gutter">
<Module class="tw-col-span-12 md:tw-col-span-4">
<ModuleHeader class="tw-border tw-border-orange-500">Module header</ModuleHeader>
<ModuleContent class="tw-border tw-border-blue-500">
<p>Module content will fill the remaining space of a module. We've added a border to illustrate this.</p>
</ModuleContent>
<ModuleFooter class="tw-border tw-border-orange-500">Module Footer</ModuleFooter>
</Module>
<Module class="tw-col-span-12 md:tw-col-span-4">
<ModuleHeader class="tw-border tw-border-orange-500">Module header</ModuleHeader>
<ModuleContent class="tw-border tw-border-blue-500">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. </p>
</ModuleContent>
<ModuleFooter class="tw-border tw-border-orange-500">Module Footer</ModuleFooter>
</Module>
<Module class="tw-col-span-12 md:tw-col-span-4">
<ModuleHeader class="tw-border tw-border-orange-500">Module header</ModuleHeader>
<ModuleContent class="tw-border tw-border-blue-500">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p>
</ModuleContent>
<ModuleFooter class="tw-border tw-border-orange-500">Module Footer</ModuleFooter>
</Module>
</section>
Table Variant
Module Table Design Examples: TODO @tyler
We have the capability to compose a Table component within a Module right now by leveraging the existing Module
and Table
components. However, there's a lot of custom style overrides and specific combination of props necessary to achieve the design.
This variant helps avoid repeating all that style customization and allows us to easily render a Table
within the child ModuleContent
component to achieve the design pattern.
The Table can be rendered within a DataView
as well if your use case calls for that.
Table inside a Module
We're rendering a Table within a Module
Product Name | Brand | Category | Price per unit | Strain |
---|---|---|---|---|
Citrus Splash 2x50mg THC Gummies | True North Collective | Edibles & Ingestibles | $2.50 | |
Rabbit Hole 1 lb bag | MJ Verdant | Flower | $2,800.00 | Hybrid |
THC-A Crystalline Rings | GMO | Kola Farms | Concentrates | $10.00 | |
Seed Junky Purple Push Pop 3.5g | Seed Junky | Flower | $20.00 | Hybrid |
GUSH-MINTS 19-23% 1.4% TERPENES | Agronomos | Flower | $1,400.00 | Indica Hybrid |
<Module variant="table">
<ModuleHeader title="Table inside a Module" description="We're rendering a Table within a Module" />
<ModuleContent>
<Table>
...
</Table>
</ModuleContent>
</Module>
API
See the documentation below for a complete reference to all the props and classes available to the components mentioned here.