@unionco/compositions
v0.0.6
Published
A css package with 13 composition classes, inspired by every layout & CUBE css. For a detailed breakdown of each composition class read the corresponding breakdown in the [css options section](#3-css-options) below. Or use the links in the table of conten
Downloads
1
Keywords
Readme
Valtech Compositions
A css package with 13 composition classes, inspired by every layout & CUBE css. For a detailed breakdown of each composition class read the corresponding breakdown in the css options section below. Or use the links in the table of contents below to go directly to a compositions definition.
Why?
Why create a package for these? These composition classes have been useful in producing flexible layouts fast. To include them in more projects we took the best parts and made them configurable so that they'll fit into your project.
Why output a css file over building html based components with tailwind classes? Because pure css may increase the size of the build a small amount, but it keeps the code dynamic and portable. Building compositions into components implicity implies a sepcific syntax. Whether that be webc, or jsx etc. Which doesn't fit as easily into as many projects as a "pure" css solution.
Why write it as a standalone css package, as opposed to a direct tailwind plugin? First because not every project uses tailwind, and this can be included in those projects. It's also not dependent on tailwind, so is less likely to break due to changes in how tailwind expects a plugin to be written. Lastly it integrates better with tailwind by being able to splice it after base styles, but before util styles so that util sytling properly overwrites composition class settings.
Put simply it's about longevity.
Table of Contents
- Installation
- Config Options
- CSS Options a. Root Compositions: b. Autogrid c. Center d. Cluster e. Cover f. Flow g. Frame h. Layer i. Reel j. Repel k. Sidebar l. Switcher m. With Icon n. Wrapper
- Integration
1. Installation & Setup
Step 1: Install with your tool of choice
- npm:
npm install --save-dev @unionco/compositions
- yarn:
yarn add -D @unionco/compositions
- npm:
Step 2: Create a config at the top level of your repo with the name
compositions.config.js
and setup an output path. If no output path is setup, it will create the file at the root of the project. Having a config is a requirement for the command to run properly so not setting an outputPath is discouraged.Example config
module.exports = { outputPath: './src/css/' /* ...your config settings here */ }
For more options see the config options below.
Step 3: Update your package.json to incorporate the
compositions
scriptStep 4: Run
yarn compositions
and the composition classes will be output into a the targeted file with the namecompositionClasses.css
2. Config Options
Global Options
outputPath
(string?:''): Determines where the css file will be generated.
minify
(boolean?:true): Determines if output css will be minified.
(Note for future integration with @valtech compositions;
)
Minification is done before adding the css content to the file.
compositionOptions
(object?:ICompositionClassesOptions): Object with settings specific to composition classes.
Composition Config Options (ICompositionClassesOptions)
classPrefix
(string?:''): Will prepend the output class names, we suggest a single character if used, such as 'c' for composition or 'l' for layout.Ex: auto-grid
-> c-auto-grid
. A -
will be added to the prefix if it does not exist. c
-> c-
, c-
-> c-
classes
(string[]?:undefined): When used limits the classes output to the ones listed within the array.
Composition Names:
- 'autogrid'
- 'center'
- 'cluster'
- 'cover'
- 'flow'
- 'frame'
- 'layer'
- 'reel'
- 'repel'
- 'sidebar'
- 'switcher'
- 'withIcon'
- 'wrapper'
Ex: classes: ['autogrid', 'flow', 'cluster', 'repel', 'sidebar']
gutter
(string?:'1rem'): Plugs into the root --gutter
variable. A css measurement value which acts as the base value for gutters in the Autogrid, Cluster, Flow, Reel, Repel, Sidebar, & Switcher compositions.
measureDefault
(string?:'70ch'): Plugs into the --measure
used for the center composition. We suggest using ch
and within a range of 50-80.
coverSpacing
(string?:'1rem'): Plugs into the --cover-spacing
variable. Used in the cover composition for space between items.
includeDefaultAspects
(boolean?:false): For the frame composition, if true will include default aspect ratio exceptions.
Ex: frame--square
& frame--circle
(along with more).
shadowboxColor
(string?:'rgba(0,0,0,.1)'): Plugs into the layer composition's shadowbox exception as the default bg color for the shadowbox.
iconClassName
(string?:'withIcon__icon'): The class name of the icon used in conjunction with the withIcon composition. This entirely replaces the class name and decouples it from the classPrefix config option.
iconSize
(string?:'0.75em'): The default size for the icon in the withIcon composition
wrapperHorPadding
(string?:'1rem'): The default horizontal padding for the wrapper composition.
Overriding any of the settings that plug into default css variable values can still be overridden through reassigning the value of the css variable. By either using :root, or by targeting an element with a specific value for a css variable.
Example config
module.exports = {
outputPath: './src/css',
minify: false,
compositionOptions: {
classPrefix: 'c-',
gutter: '2rem',
measureDefault: '60ch',
coverSpacing: '0',
includeDefaultAspects: true,
shadowBoxColor: 'rgba(70, 130, 180, .1)',
iconClassName: 'icon',
wrapperHorPadding: '2rem'
}
}
3. CSS Options
Each composition break down below contains a basic description as well as definitions for their css variables with some visual aids. Additionally some classes have exceptions and/or subclasses, these follow BEM naming conventions.
Exceptions start with double dashes and are concatenated on the end of the parent class name.
Ex: auto-grid
's column exception auto-grid--col
Subclasses start with double underscores and are classes applied to a specific child el of the parent class.
Ex: cover
's body subclass cover__body
Root CSS Variables
--gutter
(1rem): The base value for gutters used in the Autogrid, Cluster, Flow, Reel, Repel, Sidebar, & Switcher compositions.
Autogrid
A grid layout that will flex according to screen size. The number of columns, item size, and space between are setup as configurable css variables.
TODO: Images
CSS Variables:
--gutter
(1rem): Defines the space between each item.
--auto-grid-gutter
(--gutter): A composition specific --gutter
override
--auto-grid-min-item-size
(16rem): How large each item should be ideally, as a minimum.
--auto-grid-placement
(auto-fill): Set either auto-fit or auto-fill to change how empty grid tracks are handled.
--num-of-cols
(2): For the auto-grid--col exception, sets the desired number of columns.
Exceptions:
--col
: Changes the grid-placement & min-item-size to ensure a certain number of columns in the grid. This defaults to 2, but can be updated to any number using the --num-of-cols
css variable.
Setup:
<!-- Basic setup -->
<div class="auto-grid">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
<!-- ...etc -->
</div>
<!-- Set columns exception w/ tailwind -->
<div class="auto-grid auto-grid--col [--num-of-cols:4]">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
<div>Item 4</div>
<!-- Below will appear in new row -->
<div>Item 5</div>
<!-- ...etc -->
</div>
Center
A centerting composition based on character count to keep text content readible. Leveraging the ch measurement to set the max-width of text lines to a concise length.
TODO: Images
CSS Variables:
--measure
(70ch): The max width of the centered content, using character count.
Exceptions:
--intrinsic
: Centers the content based on it's width, but not beyond the max-width. Useful when you want to center something shorter than the max character count.
Setup:
<!-- Default -->
<div class="center">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed eget velit
lacinia, dignissim turpis elementum, mattis sem. Aenean id eros fringilla,
ultricies arcu in, gravida diam. Donec mattis venenatis massa vitae
accumsan. Quisque vel lacinia orci. Aliquam porta purus rhoncus auctor
lacinia. Etiam lobortis eget augue vitae placerat. Morbi ut nisi sapien.
</p>
</div>
<!-- Intrinsic exception -->
<!-- The center element will only be as wide as the content that fills it. -->
<div class="center">
<p>Lorem ipsum dolor sit amet.</p>
</div>
Cluster
A horizontal layout composition that adds space between items.
TODO: Images
CSS Variables:
--gutter
(1rem): Defines the space between each item.
--cluster-gutter
(--gutter): This defines the space between each item. Defaults to global --gutter.
--cluster-horizontal-alignment
(flex-start): This controls the position of items horizontally using flex.
--cluster-vertical-alignment
(center): This controls the position of items vertically using flex.
Setup:
<div class="cluster">
<!-- any # of items -->
<div></div>
<div></div>
<div></div>
</div>
Cover
A flex component for vertically centering items with the possibility of a header and footer. Useful for Hero's.
TODO: Images
CSS Variables:
--min-height
(100vh): Controls the minimum height for outer container.
--cover-spacing
(1rem): Space between inner elements.
--cover-padding
(0): Controls the padding of the outer element.
Subclasses:
cover__body
: Defines the center section of the cover composition.
Setup:
<div class="cover">
<div>Header</div>
<div class="cover__body">Body</div>
<div>Footer</div>
</div>
Flow
A vertical composition adds spacing between elements.
TODO: Images
CSS Variables:
--gutter
(1rem): Defines the space between each item.
--flow-space
(--gutter): Determines the amount of space between items.
Setup:
<div class="flow">
<!-- any # of items -->
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</div>
Nested Flows
Nesting a flow directly inside of another flow is a common structure. A known issue with this is a clashing value between the parent flows spacing declaration and the child element. This occurs because the flow targets the spacing of the child element with the css variable. So if you directly set the css value on a nested flow then it's parent declaration is overwritten.
A simple solution is to add an extra element between them. If you don't want to include or can't include an extra el between them there's an easy css alternative. The solution is to use the > *
css selector when setting the css variable --flow-space
. This prevents the nested flow from reseting the --flow-space
variable set by it's parent. This can be done either through a custom class specific to a component. Or done as a utility with preprocessors like scss by looping over an array of common space values with an exception like flow-space--inner
. Or if working with tailwind by utilizing an arbritray select and class [&>*]:[--flow-space:1rem]
.
Working with nested flows example
<!-- Don't do this -->
<div class="c-flow [--flow-space:4rem]">
/* Larger amount of spacing */
<div class="c-flow">
<div>Sub item 1</div>
<div>Sub item 2</div>
</div>
<!-- Space above is incorrectly 1rem instead of 4rem -->
<div class="c-flow [--flow-space:1rem]">
<div>Sub item 1</div>
<!-- spacing inside is 1rem -->
<div>Sub item 2</div>
</div>
<!-- space above is 4rem -->
<div class="c-flow">
<div>Sub item 1</div>
<div>Sub item 2</div>
</div>
</div>
<!-- Extra element solution -->
<div class="c-flow [--flow-space:4rem]">
<!-- Larger amount of spacing -->
<div class="c-flow">
<div>Sub item 1</div>
<div>Sub item 2</div>
</div>
<!-- Space between div's 1 & 2 is correctly 4rem. -->
<div>
<div class="c-flow [--flow-space:.5rem]">
<div>Sub item 1</div>
<div>Sub item 2</div>
</div>
</div>
<div class="c-flow">
<div>Sub item 1</div>
<div>Sub item 2</div>
</div>
</div>
<!-- Tailwind Solution -->
<div class="c-flow [--flow-space:4rem]">
<!-- Larger amount of spacing -->
<div class="c-flow">
<div>Sub item 1</div>
<div>Sub item 2</div>
</div>
<!-- Space between nested flow 1 & 2 is correctly 4rem. -->
<div class="c-flow [&>*]:[--flow-space:.5rem]">
<div>Sub item 1</div>
<div>Sub item 2</div>
</div>
<div class="c-flow">
<div>Sub item 1</div>
<div>Sub item 2</div>
</div>
</div>
Frame
A media based composition that keeps an aspect ratio while clipping extra content. TODO: Images
CSS Variables:
--n
(number:16): Numerator, or width
--d
(number:9): Denominator, or height
Exceptions:
To have access to frame exceptions enable includeDefaultAspects
in the config file. This adds common aspect ratios as exceptions.
--square
: 1/1--circle
: 1/1 with border-radius 50%--aspect-4-3
: 4/3, full screen aspect--aspect-6-13
: 6/13, mobile protrait
Setup:
<!-- Default -->
<div class="frame">
<img src="your-img.jpg" />
</div>
<!-- With custom values using tailwind -->
<div class="frame [--n:3] [--d:2]">
<img src="your-img.jpg" />
</div>
Layer
A simple layout that fills it's parent container, functionally similar to an adobe applications layer.
TODO: Images
CSS Variables:
--layer-position
(absolute): A CSS position value
Exceptions:
--shadowbox
: Gives the layer a background color and makes it selectable for shadow box close functionality.
Setup:
<!-- Default -->
<div class="relatvie">
<div>
<!-- Content determining size -->
</div>
<div></div>
</div>
<!-- Shadowbox exception -->
<body>
<main>
<!-- Main website content -->
</main>
<div class="layer layer--shadowbox align-center flex justify-center">
<div class="modal"></div>
</div>
</body>
Reel
A horizontally scolling content frame, that can house any number of items.
TODO: Images
CSS Variables:
--reel-height
(auto): Controls the height of the reel
--reel-item-width
(auto): Controls the width of items within the reel
--reel-spacing
(--gutter): Controls the spacing between items, and spacing in overflow exception
--reel-item-spacing
(--reel-spacing): Controls the spacing between items, overrides --reel-spacing
--reel-overflow-spacing
(--reel-spacing): Controls space after the last item in a reel. Only applicable to reels with the --overflowing
exception class
Exceptions:
--overflowing
: Adds space after the last item
Setup:
<div class="reel">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<!-- can be any element type such as img, with any # of items -->
</div>
Repel
A horizontal layout that pushes items away from each other when there is space, then stacks vertically. This is similar to the cluster and works best with 2 items
TODO: Images
CSS Variables:
--gutter
(1rem): Defines the space between each item.
--repel-gutter
(--gutter): Composition override for --gutter.
--repel-vertical-alignment
(center): How items should align vertically. Can be set to any acceptable flexbox alignment value.
Exceptions:
--single-justify-end
: Exception for repels that conditionally have one item. Where on the condition that it has one item that item should be at the end not the begining.
Setup:
<div class="repel">
<div></div>
<div></div>
</div>
Sidebar
A horizontal layout for 2 items where one acts as a sidebar.
TODO: Images
CSS Variables:
--gutter
(1rem): Defines the space between each item.
--sidebar-gutter
(--gutter): Composition override for --gutter
--sidebar-width
(10rem): A target width for the sidebar element
--sidebar-content-min-width
(50%): The minimum size of the main content area before break
Exceptions:
--ltr
: Sidebar sits on the left hand side, main content on right
--trl
: Sidebar sits on the right hand side, main content on left
Setup:
<div class="sidebar sidebar--lrt">
<div>This will be sidebar</div>
<div>This will be the main content</div>
</div>
<div class="sidebar sidebar--rtl">
<div>This will be the main content</div>
<div>This will be sidebar</div>
</div>
Switcher
A horizontal layout when given enough room that snaps to a single column when collapsing.
TODO: Images
CSS Variables:
--gutter
(1rem): Defines the space between each item.
--switcher-gutter
(--gutter): Composition override for --gutter
--switcher-threshold
(30rem): The threshold where items will switch between layouts, from horizontal to vertical.
Exceptions:
--threshold-${x}
: Where x is 2-5. This allows items past the max-items to collapse naturally like the cluster or repel. But once there's no room for the max-items will break to a single column.
Setup:
<!-- Default -->
<div class="switcher">
<!-- Any # of items dependent on space available versus item size -->
<div></div>
<div></div>
<div></div>
</div>
<!-- Max-items exception example -->
<div class="switcher switcher--thresold-3">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
With Icon
Composition for icon & text to align them both properly. It's primary use is for icons that appear directly next to short lines of text. With the goal of having the icon be a similar size as the text.
TODO: Images
CSS Variables:
--icon-spacing
(.5em): Space between icon and other item
--icon-size
(.75em): Controls the size of the icon
Subclasses:
withIcon__icon
: The class to apply to the icon, can be overriden in the config to a custom class name. If the iconName
option is used in the config, it will be detached from the prefix option.
Setup:
<!-- Icon left -->
<p class="withIcon">
<svg class="withIcon__icon"></svg>
<span>Lorem ipsum</span>
</p>
<!-- Icon right -->
<p class="withIcon">
<span>Lorem ipsum</span>
<svg class="withIcon__icon"></svg>
</p>
Wrapper
A horizontally centered wrapper that provides a consistent central column.
TODO: Images
CSS Variables:
--wrapper-width-max
(75rem): A fallback property that is used when clamp is unavailable. When updating the --wrapper-width this is typically the high end of the clamp.
--wrapper-width
(clamp(16rem, 95vw, 75rem)): A flexible width done using clamp
--wrapper-padding
(0): The inline (hor) padding of the element
Setup:
<!-- Default -->
<div class="wrapper">
<div></div>
</div>
<!-- Full bg example -->
<body>
<!-- Apply bg to wrapping element -->
<div class="bg-blue">
<!-- Use wrapper for inner content -->
<div class="wrapper">
<div></div>
</div>
</div>
</body>
Cut compositions
In previous iterations of these compositions classes there were some additional classes that I've chosen to cut. Individual reasons for each cut is below.
- Box Why? It's not inherintly useful enough. The most useful feature it provided was color inversion. But with the way that designers work with colors the cascade here tends to get in the way more than be useful.
- Breakout Why? I prefer the layer, which requires an extra div but avoids negative margins and works with flex to center items.
- Imposter Why? Again I prefer the layer. The intended purpose of the imposter is to cover modals, but by using the layer for absolute positioning creating a modal with the layer allows for more Flexibility. It allows for the modal itself to not be position absolute allowing it to work within the confines of a design system better.
4. Integration
CSS
For a pure css output define an output path pointing to your projects styles directory.
Then inside of terminal run npm compositions
or yarn compositions
depending the projects package manager.
Running the compositions
script will create a new CSS file at the specific output path with the name, controlled by the settings defined in the config.
Then simply link the stylesheet
<link rel="stylesheet" href="css/compositionClasses.css" />
Or use any other valid means of including css such as
Postcss & Tailwind
For post CSS integration see the postcss package for compositions. TODO: Add link here
CSS in JS/TS
This package exports a function named compositionClasses
, that takes the compositionOptions
of the what would go into the config and returns a string of css content. The string can be included into css in js through string literals.
import { compositionClasses } from '@unionco/compositions'
const compositionClassesSTR = compositionClasses({ ...options })