Meet ContainCSS

The Simple Svelte Component Library that uses css variables & container queries to make your life easier.

ContainCSS

Themes

Simple Components

Presenting the simple components you would expect to see in any modern component library.

Using svelte components is easy and supports a number of intuitive properties, such as:

<Button 
  bg="green" 
  fg="white" 
  width="64px" 
  height="64px">
  Wow
</Button>

Which produces:

CSS Variables

Our shorthand properties like bg and fg are just syntactic sugar for CSS variables scoped to components, like --card-bg and --button-width.

Because we use CSS variables, you can inject variables wherever you like in your component heirarchy, as in this nav bar with custom buttons:

<Bar --bar-bg="#333"
  --button-bg="#333"
  --button-fg="#eee"
  --button-height="3rem">
  <Button>Home</Button>
  <Button>About</Button>
  <Button>Contact</Button>
</Bar>

Container Queries

We use container queries out of the box, so you can adjust the layout of your components based on their size, rather than relying only on the viewport size. This "Card" has a sidebar, for example, but because the card is small, the sidebar will be in the "expander" small mode in the card, regardless of the screen size.

CSS Variables

About Variables

CSS Variables naturally flow down your component heirarchy, which makes them an ideal way to handle theming and styling in a modern component framework.

Contain has specific variables for each type of component, but those variables inherit smart defaults from some top-level settings by default.

The result is a modular system, where you can go in and customize, e.g., the padding on a button if your heart desires, but if you would like to keep everything sane and consistent, you can do so by tweaking a few top-level variables and letting inheritance do the rest.

So, for example, all elements with a border inherit the --border-radius variable out of the gate, so if you just want your whole app to feel square, you can set --border-radius to 0 and be done with it, but if you would like to get more granular, you can go in and tweak --card-border-radius and --button-border-radius and so forth.

Variables for color

Variables for typography

Variables for layout

Sample Card

Here is a little text.

Typography

If you wrap an element in a TextLayout container, we will automatically apply some basic typography for body text, headers, and so forth.

The TextLayout element uses some of the typographic styles that are applied at our top level component, which you can define anywhere in your project that you'd like to make changes.

The Typography Triangle

The key to good typography is paying attention to the harmony and balance of three simple factors:

  1. Font: the font (font-family and font-size in combination).
  2. Width: the width of each line.
  3. Spacing: the spacing between lines (line-height).

In this system, you can customize those three elements with --body-font-family, --line-width and --line-height.

Headings

We take some pains to clean up the space around headings by default, so that headings are closer to the content they describe than the content that precedes them.

If you want to use background colors on your heading, you should add some padding to them using the --heading-pad variable, which is unset by default (since our default headings don't have a background color). I recommend trying one of the existing spacing utility variables such as var(--padding) or var(--gap) or var(--space) to make sure the space around the heading will harmonize with space elsewhere in your interface.


    <TextLayout>
      <h2>Typography</h2>
      <p>And so on...</p>
      <h3>More Headings</h3>
      <blockquote>And so on</blockquote>
      <p>And <q>so</q> on.</p>
    </TextLayout>
    

Layout

Bar

The bar component is a simple flex container that can be used for menu bars, nav bars, footers, headers and more.

By default, the bar automatically spaces items out, but you can adjust that behavior either by adding left or right margins to children or by changing the CSS variables that control the justification on the flex container.

Example

Left
Center
Right
More content after the bar...

Code


  <Bar 
    --bar-bg="var(--material-color-light-blue-900)" 
    --bar-fg="var(--material-color-light-blue-100)"
    >
    <div>Left</div>
    <div>Center</div>
    <div>Right</div>
  </Bar>
  <div>More content after the bar...</div>
  

CSS Variables for Bar

Try it Out!

Try tweaking the variables for the Bar below

Cards

We provide a basic card component that can include optional header and footer slots.

Cards usually come with some box-shadow, coloring, and so forth, and have responsive sizing out of the box.

Here are some cards with and without headers inside resizable panes so you can see them acting responsively.

Cards can be set to fixedHeight true or false.

Resize.
Simplest possible card
(fixed height)
Card Header
Card body
Card foot
Card Header
Card with no feet
Card with no head
Card foot

Tiles

Tiles are flat, square containers that hold content.

They can be selectable or clickable to be used as buttons or checkboxes.

Tiles in a Grid

Basic Tile

Just a basic tile.

Tiles in cards

Card

One Tile
Two Tile

Tiles in a Split Pane

Slide the pane to see responsive tiles at work

Tiles on my Left

Look, a tile!

Tiles on my right

Look, a tile!

Columns

Small Column

Tile 1
Tile 2
Tile 3
Tile 4
Tile 5

Medium Column

Tile 1
Tile 2
Tile 3
Tile 4
Tile 5

Large Column

Tile 1
Tile 2
Tile 3
Tile 4
Tile 5

Rows

Small Row

Tile 1
Tile 2
Tile 3
Tile 4
Tile 5

Medium Row

Tile 1
Tile 2
Tile 3
Tile 4
Tile 5

Large Row

Tile 1
Tile 2
Tile 3
Tile 4
Tile 5

Components

Buttons

Our buttons are easily stylable with colors, padding,

<Button>Standard Button</Button>
<Button bg="transparent">Transparent Button</Button>
<Button>
  Icon Button
  <div slot="icon"></div>
</Button>
<Button primary={true}>Primary Button</Button>
<MiniButton bg="var(--material-color-deep-orange)" fg="white">+</MiniButton>

Try Customizing Some Buttons...

Checkboxes

<Checkbox --checkbox-checked-bg="red" bind:checked={val}>Option</Checkbox>

Checkbox CSS Variables

Customize the style of our checkboxes

Radio Buttons

<radio --radio-button-checked-bg="red" bind:checked={val}>Option</radio>

radio CSS Variables

Customize the style of our radioes

Forms

Our FormItem component is the heart of a simple approach to form layout. In a wide container, it puts labels side-by-side with inputs. In a narrow container, it puts labels above inputs. A number of CSS variables allow easy customization.

Out of the box, we auto-style inputs within a FormItem, so you don't need to import yet another custom component unless you want something fancy like a custom checkbox or select box.

You can turn off the global input styles by setting globalInputStyles to false.

Out of the box, we use nested labels for simple accessibility, so it's important that if you have a complex input, you have the first item in it the one you want focused when the user clicks the label.

Sample Code:


    <Container border --container-max-width="300px" --input-width="20em">      
      <FormItem>
        <span slot="label">Name</span>
        <input type="text" />
      </FormItem>
      <FormItem>
        <span slot="label">Age</span>
        <input type="number" min="16" max="130" />
      </FormItem>
      <FormItem>
        <span slot="label">Level</span>
        <input type="range" />
      </FormItem>
      <FormItem>
        <Button primary>Add</Button>  
      </FormItem>
    </Container>    
    

Result:

FormItem CSS Variables

Customize the style of our form items

Remember, because these are CSS variables, they don't have to be added at the FormItem component level but can be added higher up the heirarchy.

In a wide container

In a narrow container

TabItem

TabItem is basically syntactic sugar for a special button.

We provide an active= property to set it to active or not.

TabItem then overrides some of the button variables with tab variables which have their own defaults, specifically:

  • Button radius (defaults to rounded tops)
    • tab-border-bottom-right-radius
    • tab-border-top-right-radius
    • tab-border-bottom-left-radius
    • tab-border-top-left-radius
  • Button margin (default to 0 so we snuggle against a bar).
    tab-margin
<TabItem active>TabItem</TabItem>
<TabItem>TabBar</TabItem>
<TabItem>Containers & Tabs</TabItem>
<TabItem>Overrides</TabItem>      

Adjust variables to customize tabs

Page

The <Page> component providers a simple full screen layout, designed to be used with header/footer/sidebar or not.

The page defaults to full width and 100vh, but can take width and height properties to constrain it, as in the embedded demo page below.

Header
Header
Header

Slot Options


  <Page>
    <Bar slot="header">...</Bar>
    <Bar slot="footer" marginBottom="0">...</Bar>
    <Sidebar slot="sidebar" >...</Sidebar>
    <div>Page content here</div>
  </Page>
  
Footer
Footer
Footer

Split Pane

The <SplitPane> component makes it simple to create divided content in resizable panes. Users can set the initial size by passing left and right widths as props.

A min-size prop determines when the pane will "snap" to closed instead of shrunken.

Finally, panes automatically stack when placed in a small enough component.

These panes are rendered with:

<SplitPane leftWidth={2fr} rightWidth={1fr}>
  <div slot="left">...</div>
  <div slot="right">...</div>
</SplitPane>
            
Oh how amazing there is also content on the right.

A Card!

Here is a card so we can we can see responsive behavior as the container changes.

Responsive

Below are some nested split panes so you can see how they behave responsively.

Stretch to change pane on the right
Inner left side
Inner right side