Welcome to HyperUI, a personal Vue 3 component library fitting my needs.
HyperUI aims on being an easy to use, opinionated component library for Vue 3. It provides components and the necessary building blocks to design web apps, but unlike other libraries does not provide excessive customizability. HyperUI supports automatic darkmode based on the users system preferences.
As this library is a personal project, it does not come with a lot of customization options, but in this documentation there are some tips on how to customize the design using CSS. If you think like there is something off with your design, then feel encouraged to use CSS to tweak it the way you like it.
Licensed under MIT License.
- Attention Breaking Changes
- Install and import
-
Component Documentation
- Button
- Input
- TextArea
- Select
- SelectDropdown
- Checkbox
- Toggle
- RadioButton
- Dropzone
- Tabbar
- Loader
- ProgressBar
- FlexContainer
- Section
- SubSection
- Table
- Main
- NavigationContainer
- NavigationSidebar
- NavigationTabbar
- Dropdown
- Modal
- Popover & Tooltip
- Popover Free
- Smart Menu
- Smart Menu Free
- ListIcon
- Header
- Split View
- Floating Badges
- CSS Documentation
- Tips & Tricks
- Changelogs
Upgrading to Version 3.0.0:
We refined the naming scheme of this library. Please search your codebase for these classes and replace them with:
OLD | NEW | |
---|---|---|
reset |
--> | hy-reset |
--font-color-similar |
--> | --font-color-match |
same |
--> |
match (only affects HyPopover, HyPopoverFree, HySmartMenu and HySmartMenuFree) |
We also changed targeting classes and utility classes to fit this new naming scheme. We strongly incourage you to use the new syntax. With this syntax, every class now matches its corresponding component name:
OLD | NEW | |
---|---|---|
hyper-button |
--> | hy-button |
hyper-checkbox |
--> | hy-checkbox |
hyper-dropzone |
--> | hy-dropzone |
hyper-flexcontainer |
--> | hy-flex-container |
hyper-header |
--> | hy-header |
hyper-input |
--> | hy-input |
hyper-listicon |
--> | hy-list-icon |
hyper-loader |
--> | hy-loader |
hyper-main |
--> | hy-main |
hyper-modal |
--> | hy-modal |
hyper-navigationcontainer |
--> | hy-navigation-container |
hyper-navigationsidebar |
--> | hy-navigation-sidebar |
hyper-navigationtabbar |
--> | hy-navigation-tabbar |
hyper-popover |
--> | hy-popover |
hyper-popoverfree |
--> | hy-popover-free |
hyper-progressbar |
--> | hy-progress-bar |
hyper-radiobutton |
--> | hy-radio-button |
hyper-section |
--> | hy-section |
hyper-select |
--> | hy-select |
hyper-smartmenu |
--> | hy-smart-menu |
hyper-smartmenufree |
--> | hy-smart-menu-free |
hyper-subsection |
--> | hy-sub-section |
hyper-tabbar |
--> | hy-tabbar |
hyper-table |
--> | hy-table |
hyper-textarea |
--> | hy-text-area |
hyper-toggle |
--> | hy-toggle |
Upgrading to Version 2.0.0:
- New component naming scheme -> Please refer to the component documentation
- Styles now need to be imported manually -> Please refer to the Import Section
<script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@jaaahn/hyper-ui/dist/hyper-ui.iife.js"></script>
This will expose the global variable HyperUI
which can be used to install the library: app.use(HyperUI, config)
.
Importing styles is not required if importing from a CDN.
npm install @jaaahn/hyper-ui
// Standard Vue Code
import { createApp } from "vue";
import App from "./App.vue";
const app = createApp(App);
// Standard Vue Code above
// #######################
// See below for config options; these can be omitted
let config = {
theme: "system",
size: "normal",
};
import HyperUI from "@jaaahn/hyper-ui";
app.use(HyperUI, config); // config is optional and can be omitted
import "@jaaahn/hyper-ui/styles"; // Import styles !IMPORTANT!
// #######################
// Standard Vue Code below
app.mount("#app");
This is all you need. Now you can use these components within your template. You don't need to import them in each file and you also don't need to put them within you components
object in your Vue instance as you would do it with your own custom components.
HyperUI allows you to change its behaviour by providing a config.
This config is a JS object
passed to the app.use(...)
function as the second argument (see above). But, passing this is completely optional and the config can just be omitted if one does not want to change the libraries behaviour.
Name | Type | Default | Possible values | Extra info |
---|---|---|---|---|
theme |
String | "system" |
"system" , "light" or "dark"
|
system will choose light- or darkmode depending on the users system preferences |
size |
String | "normal" |
"normal" , "light" or "thin"
|
Only on supported elements |
If you are planning on using the included HyHeader component, please add these theme-color meta tags to your html head:
<meta name="theme-color" content="#fff" media="(prefers-color-scheme: light)" />
<meta name="theme-color" content="#191c1f" media="(prefers-color-scheme: dark)" />
If you are NOT planning on using the Header, then add the following to your html head:
<meta name="theme-color" content="#eeeef2" media="(prefers-color-scheme: light)" />
<meta name="theme-color" content="#0c0c0e" media="(prefers-color-scheme: dark)" />
Component names can be written in Camel Case with the first letter also capitalized, like "HyFlexContainer" or "HyButton". Alternatively you can also write the components in lowercase syntax like "hy-flex-container" or "hy-button".
Mind you: If passing a non string to a prop, you need to use v-bind:PROPNAME
. Otherwise you will get a warning in your console.
Basic <button>
element. It comes in two colors, can be disabled and put into a loading state.
hy-button
Pass a slot which will be displayed as the normal <button>
text.
Name | Type | Default | Extra info |
---|---|---|---|
type |
String | "secondary" |
See down below |
size |
String | normal |
Size Option Docs |
loading |
Boolean | false |
For spinner: leave progress = null. For progress bar: provide a progress value between 0-1 |
disabled |
Boolean | false |
|
extend |
Boolean | true |
Controls wether the element extends to 100% or stays at max-content . Not recommended, use .hy-extend-full instead. |
progress |
Number | null |
Range between 0-1. Values not in this range will be caped |
progressWidth |
String | min(70%, 150px) |
Specify a width (valid css) |
Option name | Result |
---|---|
primary |
Primary action button style featuring the blue accent color |
secondary |
Secondary action button, matches the background color |
transparent |
Button with only text. Has hover and click effect. |
transparent-bg |
Button with text and a slightly visible gray background. Has hover and click effect. |
light-blue |
Compare to above |
light-bg-blue |
Compare to above |
light-red |
Compare to above |
light-bg-red |
Compare to above |
light-orange |
Compare to above |
light-bg-orange |
Compare to above |
light-green |
Compare to above |
light-bg-green |
Compare to above |
<!-- Loading with spinner -->
<hy-button @click="method('hello')" :disabled="false" :loading="isLoading" type="primary">
Click me
</hy-button>
<!-- Loading with progress -->
<hy-button @click="method('hello')" :disabled="false" :loading="isLoading" :progress="loadingProgress" type="primary">
Click me
</hy-button>
Every HyButton
component is a <button>
nested inside a <div>
element (see Re-Styling Components).
The specific styles (controlled by the type
option) are applied to the <button>
element by a class, which matches the type's name.
So, if you want to change the background-color of every transparent button, you could use something like:
.hy-button :deep(button.transparent) {
background-color: yellow !important;
}
/* :deep() is explained in the "Re-Style Components" section */
Basic <input>
element. It can be disabled and put into an loading state.
Use v-model
to create a two-way binding.
hy-input
Syncs the current input value with your parent vue instance. View the Info about v-model section for more details.
Name | Is also the default slot | Extra info |
---|---|---|
left |
Yes | Position: left |
right |
No | Position: far right |
Name | Type | Default | Extra info |
---|---|---|---|
modelValue |
any | - | Required. Two-way binding for the input's value |
type |
String | "text" |
Equal to HTML's type attribute. E.g. type="password"
|
size |
String | normal |
Size Option Docs |
placeholder |
String | "" |
|
loading |
Boolean | false |
For spinner: leave progress = null. For progress bar: provide a progress value between 0-1 |
disabled |
Boolean | false |
|
extend |
Boolean | true |
Controls wether the element extends to 100% or stays at max-content . Not recommended, use .hy-extend-full instead. |
required |
Boolean | false |
Equal to HTML's required attribute. |
progress |
Number | null |
Range between 0-1. Values not in this range will be caped |
progressWidth |
String | min(70%, 150px) |
Specify a width (valid css) |
invalid |
Boolean | false |
Highlights input with red color if true |
invalidText |
String | null |
Displays a message (if invalid = true) |
The option autocomplete
got removed in favor of vue's $attrs
.
All HTML props except id
, class
and vue props listed above, will be inherited to the underlying <input>
element.
Vue will also automatically inherit all props, including id
and class
, to the <div>
wrapper that this component uses.
<hy-input v-model="username" :disabled="false" :loading="isLoading" type="text" placeholder="Your username"></hy-input>
With an Icon on the left side
<hy-input v-model="username" :disabled="false" :loading="isLoading" type="text" placeholder="Your username">
<i class="icon-search"></i>
</hy-input>
With an Icon on the right side
<hy-input v-model="username" :disabled="false" :loading="isLoading" type="text" placeholder="Your username">
<template #right>
<i class="icon-megaphone"></i>
</template>
</hy-input>
With an Icon on the left and on the right side
<hy-input v-model="username" :disabled="false" :loading="isLoading" type="text" placeholder="Your username">
<template #left>
<i class="icon-search"></i>
</template>
<template #right>
<i class="icon-megaphone"></i>
</template>
</hy-input>
With progress bar
<hy-input v-model="username" :disabled="false" :loading="isLoading" :progress="loadingProgress" type="text" placeholder="Your username"></hy-input>
Basic <textarea>
element with the option of being disabled.
Use v-model
to create a two-way binding.
This Component was not build for being used within a FlexContainer
.
hy-text-area
Syncs the current input value with your parent vue instance. View the Info about v-model section for more details.
Name | Type | Default | Extra info |
---|---|---|---|
modelValue |
String | - | Required. Two-way binding for the input's value |
placeholder |
String | ""
|
|
disabled |
Boolean | false |
|
required |
Boolean | false |
Equal to HTML's required attribute. |
resize |
String | vertical |
Equal to CSS resize rule. Correct values are none , both , vertical & horizontal
|
size |
String | normal |
Size Option Docs |
invalid |
Boolean | false |
Highlights input with red color if true |
invalidText |
String | null |
Displays a message (if invalid = true) |
All HTML props except id
, class
and vue props listed above, will be inherited to the underlying <textarea>
element.
Vue will also automatically inherit all props, including id
and class
, to the <div>
wrapper that this component uses.
<hy-text-area v-model="essay" :disabled="false" placeholder="Your essay goes here" />
A HTML select
element with custom styling and an icon.
Use v-model
to create a two-way binding.
hy-select
Syncs the selected option with your parent vue instance. View the Info about v-model section for more details. This allows you to programmatically set the value while still allowing the user to select the option he wants.
Name | Is also the default slot | Extra info |
---|---|---|
options |
Yes | Pass the <option> elements as you would with regular HTML |
icon |
No |
Name | Type | Default | Extra info |
---|---|---|---|
modelValue |
String | - | Required. Two-way binding about the selected option |
loading |
Boolean | false |
For spinner: leave progress = null. For progress bar: provide a progress value between 0-1 |
disabled |
Boolean | false |
|
extend |
Boolean | true |
Controls wether the element extends to 100% or stays at max-content . Not recommended, use .hy-extend-full instead. |
size |
String | normal |
Size Option Docs |
progress |
Number | null |
Range between 0-1. Values not in this range will be caped |
progressWidth |
String | min(70%, 150px) |
Specify a width (valid css) |
invalid |
Boolean | false |
Highlights input with red color if true |
invalidText |
String | null |
Displays a message (if invalid = true) |
<hy-select v-model="variable" :disabled="false" :loading="isLoading">
<option value="option1">Option 1</option>
<option value="option2">Option 2</option>
</hy-select>
With an icon:
<hy-select v-model="variable" :disabled="false" :loading="isLoading">
<template #options>
<option value="option1">Option 1</option>
<option value="option2">Option 2</option>
</template>
<template #icon>
<i class="icon-sort-descending"></i>
</template>
</hy-select>
With progress bar
<hy-select v-model="variable" :disabled="false" :loading="isLoading" :progress="loadingProgress">
<option value="option1">Option 1</option>
<option value="option2">Option 2</option>
</hy-select>
Similar to a hy-select
but comes with its own menu UI and search functionality. Utilises hy-dropdown
under the hood.
hy-select-dropdown
Syncs the selected option with your parent vue instance. View the Info about v-model section for more details. This allows you to programmatically set the value while still allowing the user to select the option he wants.
Name | Is also the default slot | Extra info |
---|---|---|
options |
Yes | Specify icons as follows: <p data-value="internalValue"> Display Value </p>
|
icon |
No |
Name | Type | Default | Extra info |
---|---|---|---|
modelValue |
String | - | Required. Two-way binding about the selected option |
enableSearch |
Boolean | true |
Disable the search bar |
searchPlaceholder |
String | "Search..." |
|
searchNoResults |
String | "No search results found..." |
|
invalid |
Boolean | false |
Highlights input with red color if true |
invalidText |
String | null |
Displays a message (if invalid = true) |
Additionally, this menu supports these properties from HyDropdown:
border
, loading
, progress
, progressWidth
, disabled
, size
, maxHeight
, zIndex
, hideOnClickOutside
, dropdownDirection
<hy-select-dropdown v-model="variable">
<p data-value="option1">Option 1</p>
<p data-value="option2">Option 2</p>
<p data-value="option3">Option 3</p>
<p data-value="option4">Option 4</p>
</hy-select-dropdown>
Or with an icon (syntax equal to hy-select)
<hy-select-dropdown v-model="variable">
<template #options>
<p data-value="option1">Option 1</p>
<p data-value="option2">Option 2</p>
<p data-value="option3">Option 3</p>
<p data-value="option4">Option 4</p>
</template>
<template #icon>
<i class="icon-sort-descending"></i>
</template>
</hy-select-dropdown>
Standard checkbox. It can be disabled.
Use v-model
to create a two-way binding.
hy-checkbox
Syncs whether the box is ticked or not with your parent vue instance. View the Info about v-model section for more details.
Use the slot to pass text which will be displayed as a label.
Name | Type | Default | Extra info |
---|---|---|---|
modelValue |
Boolean | - | Required. Two-way binding for the checkbox's value |
disabled |
Boolean | false |
|
extend |
Boolean | true |
Controls wether the element extends to 100% or stays at max-content . Not recommended, use .hy-extend-full instead. |
type |
String | left |
left or right . Aligns either label and box left, or label on the left and box on the right |
<hy-checkbox v-model="someBooleanVariable" :disabled="disabledVariable" type="right">
Click me
</hy-checkbox>
An iOS style toggle "checkbox". Sometimes this is also called a "switch".
This component is functionally identical to the <hy-checkbox>
component. Please refer to its documentation.
<hy-toggle v-model="someBooleanVariable" :disabled="disabledVariable" type="right">
Toggle me
</hy-toggle>
Standard radio button. It can be disabled.
Use v-model
to create a two-way binding.
hy-radio-button
Syncs which radio button is selected with your parent vue instance. View the Info about v-model section for more details. This allows you to programmatically set the value while still allowing the user to select the option he wants.
Use the slot to pass text which will be displayed as a label.
Name | Type | Default | Required | Extra info |
---|---|---|---|---|
modelValue |
String | - | Required | Two-way binding about wether the radio is selected or not. |
value |
String | - | Required | Value of your radio button. If the radio button is clicked, this will be written to your modelValue variable. Works similar to html's <option value="..."> -tag one uses within selects. |
name |
String | - | - | Set the name attribute of the <input type="radio"> -tag used within the component. |
disabled |
Boolean | false |
- | |
type |
String | left |
- | Set to left or right . Aligns either label and box left, or label on the left and box on the right. |
extend |
Boolean | true |
- | Controls wether the element extends to 100% or stays at max-content . Not recommended, use .hy-extend-full instead. |
<!-- These three components will form a radio group, where only one option can be selected at a time. -->
<hy-radio-button v-model="someVariable" value="option1" :disabled="disabledVariable"> Option 1 </hy-radio-button>
<hy-radio-button v-model="someVariable" value="option2" :disabled="disabledVariable"> Option 2 </hy-radio-button>
<hy-radio-button v-model="someVariable" value="option3" :disabled="disabledVariable" type="right"> Option 3 </hy-radio-button>
A dropzone component. Drop a file or click on it to open a native file selector window.
hy-dropzone
Name | Type | Default | Required | Extra info |
---|---|---|---|---|
placeholder |
String | "Drop file here or click to select a file" |
- | |
readMode |
String | "text" |
- | How the file will be read. Choose between text , binaryString , dataURL or arrayBuffer . More info about what they do
|
accept |
String | * |
- | Which files to accept. About this attribute and how its syntax works |
Once the user selects a file, the newValue
event will be fired with an event object containing the following information:
{
content: String,
name: String,
size: Number,
lastModified: Number,
type: String // MIME-Type of the selected file
}
If one wants to clear the selected file, please call the clear
method on the component instance. If this method is called, the newValue
event will fire with $event = null
.
Guide on how to do this using Vue refs:
<hy-dropzone
readMode="dataURL"
accept="image/*"
@newValue="my_method_for_handling_the_event($event)"
ref="myDropzone"
/>
<hy-button @click="$refs.myDropzone.clear()"> Clear </hy-button>
The underlying <input type="file">
html element is the second child node of the dropzone component. Thus is can be direcly referenced:
<hy-dropzone ref="myDropzone" />
let inputElement = this.$refs.myDropzone.$el.childNodes[1];
Hint: In Vue, the $event
is the variable that contains the event object of the triggered event.
<hy-dropzone readMode="text" accept="text/*,application/*,.md" @newValue="myVariable = $event" />
Or:
<hy-dropzone readMode="dataURL" accept="image/*" @newValue="my_method_for_handling_the_event" />
Or:
<hy-dropzone readMode="dataURL" accept="image/*" @newValue="my_method_for_handling_the_event($event)" />
A tabbar with multiple tabs the user can switch between. Sometimes this is known as a segmented picker or a switch.
Use v-model
to create a two-way binding, much like the <Select>
works.
This component supports dynamically created options (e.g. if using a v-for
loop for generating options).
If there are too many options to fit them, the component will automatically allow the user to scroll through the options. For this to work, the component may not be wrapped in a display: flex
container or a hy-flex-container
!
hy-tabbar
Syncs the selected tab with your parent vue instance. View the Info about v-model section for more details.
Pass all of the options in this syntax: <p data-value="valueOfTab"> Display Value </p>
.
Name | Type | Default | Extra info |
---|---|---|---|
modelValue |
String | Required. Two-way binding about which tab is selected | |
disabled |
Boolean | false |
|
type |
String | gray |
Available options are gray and blue
|
<hy-tabbar v-model="variable" :disabled="disabledVariable">
<p data-value="tab1">Tab 1</p>
<p data-value="tab2">Tab 2</p>
<p data-value="tab3">Tab 3</p>
</hy-tabbar>
This is a custom loading indicator.
Use v-if="booleanVariable"
to show the indicator or not.
This is just a spinning wheel, you must position the indicator by yourself.
hy-loader
Name | Type | Default | Extra info |
---|---|---|---|
width |
Number | 50 |
In css px |
height |
Number | 50 |
In css px |
line |
Number | 4 |
In css px. This is how thick the line is rendered |
<hy-loader v-if="isLoading" :width="25" :height="25" :line="3" />
This is a custom progress bar.
hy-progress-bar
Name | Type | Default | Extra info |
---|---|---|---|
progress |
Number | - | Required. Range between 0-1. Values not in this range will be caped |
width |
String | "100%" |
Specify a width (valid css) |
<hy-progress-bar v-if="isLoading" :progress="loadingProgress" width="50%" />
This is basically a div
with display: flex
applied to it. If the screen is smaller than 800px, the flex-direction
will be set to column
hy-flex-container
Pass the elements you want to position within the FlexContainer via the slot.
Name | Type | Default | Extra info |
---|---|---|---|
wrap |
Boolean | true |
Controls the css flex-wrap property, switches between wrap and no-wrap
|
justify |
String | space-between |
Controls the css justify-content property |
verticalAlign |
String | center |
Controls the css align-items property |
direction |
String | row |
Controls the css flex-direction property |
allowBreak |
Boolean | true |
Wether the flex-container should switch to flex-direction: column if the screen is smaller than 800px |
Your items will shrink to the minimum width without shrinking your content (e.g. text). If you would like to change this behaviour, please do this manually in your css.
<hy-flex-container>
<input />
<button>Hello</button>
<hy-checkbox />
</hy-flex-container>
This is a section, with (unlike the body) a white background. It should be used most of the time when working with content. A section includes a title and two description fields.
hy-section
Pass the elements you want to position within the Section via the slot.
If provided alongside a value for title
, the section becomes collapsable.
Omit this, if you don't want the section to be collapsable (default behaviour).
View the Info about v-model section for more details.
Any title
, pre
or post
field left as null won't be rendered.
Name | Type | Default | Extra info |
---|---|---|---|
border |
Boolean | false |
|
divider |
Boolean | false |
A divider between each element will be added automatically if set to true |
title |
String | null |
|
pre |
String | null |
Description field over slot |
post |
String | null |
Description field under slot |
modelValue |
Boolean | null |
Collapse the section (only active, if a value for title is provided) |
<hy-section :border="true" :divider="false">
<hy-flex-container>
<input />
<hy-button>Hello</hy-button>
<hy-checkbox />
</hy-flex-container>
</hy-section>
<hy-section title="My Section" pre="Description" v-model="testSectionCollapsed">
<hy-button>Hello</hy-button>
</hy-section>
Has a slightly darker background-color than a section. Intended for use with only one input / button (etc.) element but one can pass any element via the slot. A sub-section includes a title and two description fields.
hy-sub-section
Pass the element(s) you want to position within the Sub-Section via the slot.
If provided alongside a value for title
, the sub-section becomes collapsable.
Omit this, if you don't want the section to be collapsable (default behaviour).
View the Info about v-model section for more details.
Any title
, pre
or post
field left as null won't be rendered.
Name | Type | Default | Extra info |
---|---|---|---|
title |
String | null |
|
pre |
String | null |
Description field over slot |
post |
String | null |
Description field under slot |
modelValue |
Boolean | null |
Collapse the sub-section (only active, if a value for title is provided) |
<hy-sub-section title="Title" pre="First description" post="Second description">
<hy-input v-model="testInput" placeholder="Input field" />
</hy-sub-section>
<hy-sub-section title="Title" v-model="testSubSectionCollapsed">
<hy-input v-model="testInput" placeholder="Input field" />
</hy-sub-section>
This component was designed to be used within a regular Section. That's why it has a slightly different color than normal sections. If you want them to appear with the same color as Sections, for example to use them without a wrapper section, then please add the following lines of css to your code:
.hy-sub-section {
background-color: var(--section-bg-color);
/* If you want them to have the same padding as regular sections */
padding: var(--section-padding);
}
A table.
hy-table
Pass HTML table elements.
Name | Type | Default | Extra info |
---|---|---|---|
border |
Boolean | true |
<hy-table :border="true">
<tr>
<th>Col 1</th>
<th>Col 2</th>
</tr>
<tr>
<td>Hello</td>
<td>World</td>
</tr>
</hy-table>
A container that resizes based on your screen size. At a certain screen size it locks to a width of 1400px (or whatever you specify it to).
hy-main
Pass the elements you want to position within the Main view via the slot.
Name | Type | Default | Extra info |
---|---|---|---|
maxWidth |
String | "1400px" |
Desired css max-width value |
resizeTo |
Number | 95 |
Will be a max-width in percent that the container will resize to if it must be smaller than the given maxWidth
|
<hy-main maxWidth="800px" :resizeTo="90">
<hy-flex-container>
<input />
<button>Hello</button>
<hy-checkbox />
</hy-flex-container>
</hy-main>
HyperUI comes with a basic navigation system consisting of a sidebar and a tabbar UI component.
If you just provide a Sidebar and Tabbar component, then the container will display the sidebar on desktop devices and the tabbar on mobile devices. It uses the switchToMobileAt
prop to decide which to use when.
Optionally, you may use the sidebarVisibleDesktop
v-model (which defaults to true) to hide/show the sidebar on desktop devices.
If you use the sidebarVisibleMobile
v-model (which defaults to false), you can also hide/show the sidebar on mobile devices. The sidebar will then render over the main content and clicking outside of it will close it.
Using this does not void your option to use the tabbar component on mobile. You could, if you wish so, use the tabbar and the sidebar in conjunction on mobile.
hy-navigation-container
Name | Is also the default slot | Extra info |
---|---|---|
tabbar |
No | Tabbar is for mobile phones |
sidebar |
No | Displayed on larger screens or if sidebarVisibleMobile is set to true
|
content |
No | Here, you may place something like the <router-view />
|
Name | Type | Default | Required | Extra info |
---|---|---|---|---|
sidebarVisibleDesktop |
Boolean | true |
- | Toggles whether the sidebar is visible or retracted on desktop |
sidebarVisibleMobile |
Boolean | true |
- | Toggles whether the sidebar is visible or retracted on mobile devices |
switchToMobileAt |
Number | 850 |
- | In CSS px . If the screen is smaller than this number, then this component will hide the sidebar and show the tabbar. |
gap |
String | "25px" |
- | Gap between sidebar and content when in desktop mode |
sidebarPosition |
String | "left" |
- |
left or right
|
sidebarDimensions |
Object | null |
- | This is just a backup for if the automatic sidebar-width-detection does not work, provide a {width: 'any css value'} value. |
<hy-navigation-container
v-model:sidebarVisibleDesktop="sidebarVisibleDesktop"
v-model:sidebarVisibleMobile="sidebarVisibleMobile">
<template #sidebar>
<hy-navigation-sidebar>
<!-- Of course, one can put in this slot whatever they want: -->
<h3>Hello World</h3>
<!-- It's recommended to use the pre-styled navigation buttons for presenting the different routing destinations -->
<button @click="$router.push('/home')" class="hy-navigation-option" :class="{ selected: $route.name == 'Home' }">
<i class="icon-home"></i> <!-- Icon -->
<span>Home</span> <!-- Label -->
</button>
<br />
<button @click="$router.push('/settings')" class="hy-navigation-option" :class="{ selected: $route.name == 'Settings' }">
<i class="icon-settings"></i>
<span>Settings</span>
</button>
</hy-navigation-sidebar>
</template>
<template #tabbar>
<hy-navigation-tabbar>
<!-- These pre-styled navigation buttons are also in the tabbar available, but they change their style to better fit in the tabbar -->
<button @click="$router.push('/home')" class="hy-navigation-option" :class="{ selected: $route.name == 'Home' }">
<i class="icon-home"></i>
<span>Home</span>
</button>
<button @click="$router.push('/settings')" class="hy-navigation-option" :class="{ selected: $route.name == 'Settings' }">
<i class="icon-settings"></i>
<span>Settings</span>
</button>
</hy-navigation-tabbar>
</template>
<template #content>
<!-- This example uses Vue Router, but essentially you can put anything in here -->
<router-view></router-view>
</template>
</hy-navigation-container>
The <hy-navigation-sidebar>
and <hy-navigation-tabbar>
components are explained below.
As part of the navigation system HyperUI offers, there is a Sidebar UI component. It should be placed within a HyNavigationContainer.
hy-navigation-sidebar
Place any content (e.g. a logo, company name and the available pages) that should be displayed within the sidebar here.
Within this slot, one may use the "hy-navigation-option"
class on a <button>
element to create a specially designed button that may represent a page that the user can visit. Apply the "selected"
class to it and it will be highlighted. Within, you can place a label next to an icon.
The following example will use vue router to create a navigation option, that represents the 'home' page of your app:
<button @click="$router.push('/home')" class="hy-navigation-option" :class="{ selected: $route.name == 'Home' }">
<!-- Icon -->
<i class="icon-home"></i>
<!-- Label -->
<span>Home</span>
</button>
Note: this syntax is identical to the syntax used in <hy-navigation-tabbar>
component.
Name | Type | Default | Required | Extra info |
---|---|---|---|---|
width |
String | "300px" |
- | |
height |
String | "100dvh" |
- | Use the dvh unit for a better experience on mobile devices |
topInset |
String | "0px" |
- | Controls the top property of the sticky sidebar visual element |
leftInset |
String | "0px" |
- | Controls the left property of the sticky sidebar visual element |
For example look at the HyNavigationContainer
's example section
As part of the navigation system HyperUI offers, there is a Tabbar UI component. It should be placed within a HyNavigationContainer.
This component looks similar to the tabbar that iOS apps typically have.
hy-navigation-tabbar
Place the available navigation options that should be displayed within the tabbar here.
Within this slot, one may use the "hy-navigation-option"
class on a <button>
element to create a specially designed button that may represent a page that the user can visit. Apply the "selected"
class to it and it will be highlighted. Within, you can place a label below an icon.
The following example will use vue router to create a navigation option, that represents the 'home' page of your app:
<button @click="$router.push('/home')" class="hy-navigation-option" :class="{ selected: $route.name == 'Home' }">
<!-- Icon -->
<i class="icon-home"></i>
<!-- Label -->
<span>Home</span>
</button>
Note: this syntax is identical to the syntax used in <hy-navigation-sidebar>
component.
Name | Type | Default | Required | Extra info |
---|---|---|---|---|
zIndex |
Number | 100 |
- |
For example look at the HyNavigationContainer
's example section
An expanding menu. The menu floats above other content (and thus is not an inline element) but remains visually attached. It therefore is the mid-ground between a popover and an expandable section.
hy-dropdown
Name | Is also the default slot | Extra info |
---|---|---|
content |
Yes | The content to display in the menu |
title |
No | If you don't want to use the title prop, you may use this slot. Note: additional styling of the element might be necessary. |
icon |
No |
Name | Type | Default | Extra info |
---|---|---|---|
modelValue |
Boolean | - | Required. Controls whether or not the dropdown is open |
title |
String | - | Required |
border |
Boolean | false |
|
loading |
Boolean | false |
For spinner: leave progress = null. For progress bar: provide a progress value between 0-1 |
progress |
Number | null |
Range between 0-1. Values not in this range will be caped |
progressWidth |
String | min(70%, 150px) |
Specify a width (valid css) |
disabled |
Boolean | false |
|
size |
String | normal |
Size Option Docs |
maxHeight |
String | null |
Specify a height (valid css) or null to leave it unconstrained |
zIndex |
Number | 10 |
Z-Index of the expanding menu |
hideOnClickOutside |
Boolean | true |
If the user clicks outside, the menu will hide |
dropdownDirection |
String | "bottom" |
"bottom" or "top"
|
invalid |
Boolean | false |
Highlights input with red color if true |
invalidText |
String | null |
Displays a message (if invalid = true) |
<hy-dropdown v-model="dropdownIsOpenVariable" title="Click to expand">
<p>Hello World</p>
</hy-dropdown>
Or with an icon (syntax equal to hy-select or hy-input)
<hy-dropdown v-model="dropdownIsOpenVariable" title="Click to expand">
<template #content>
<p>Hello World</p>
</template>
<template #icon>
<i class="icon-settings"></i>
</template>
</hy-dropdown>
A modal element. Adapts to mobile and desktop devices. Respects the bottom safe-area.
hy-modal
Syncs the current visibility state with your parent vue instance. View the Info about v-model section for more details.
If modelValue
is set to true
, the modal will show. So you can open the modal programmatically while letting the user close the modal with the build in close button.
Name | Is also the default slot | Extra info |
---|---|---|
content |
Yes | The main content of the modal |
header |
No | Place elements next to the close button. Use size="light" to match the close button. (OPTIONAL) |
Name | Type | Default | Extra info |
---|---|---|---|
modelValue |
Boolean | - | Required. Two-way binding about whether the modal is open or not |
headline |
String | null |
|
description |
String | null |
|
zIndex |
Number | 200 |
Z-Index of modal element |
background |
String | null |
Background (-color) of modal. Defaults to white (or black) |
hideScrollbars |
Boolean | true |
|
doBSL |
Boolean | true |
Whether body scrolling should be disabled or not. If doBSL = true , then the user will only be able to scroll within the modal, not the entire body. |
disableDismiss |
Boolean | false |
If set to true , the user cannot dismiss the modal. This option hides the close button and disabling the 'click-outside-way' of closing the modal. |
disableSwipeToClose |
Boolean | false |
If set to true , swipe to close on touch devices will be disabled and the close button will be shown on every device. |
forceFullHeightOnMobile |
Boolean | false |
Forces full height if the modal is displayed on mobile devices. If false , the modal will only be as high as necessary |
doBlurBg |
Boolean | false |
Be advised: we noticed the modal getting stuck on iOS when setting this option to true. |
In your vue template:
<hy-modal v-model="modal.isOpen" headline="My test modal">
<p>{{ myText }}</p>
<hy-button v-on:click="modal.isOpen = false">
Close modal
</hy-button>
</hy-modal>
A popover container. Floats above the main content and stays attached to the target element with the help of Popper. Will disappear if the user clicks outside of it.
If you set hover
to true
, then you can use this component as a tooltip.
Popovers may require a lot of computing resources. We recommend not using too many of them, certainly not in dynamic scenarios (e.g. using v-for). For such applications, please use HyPopoverFree.
hy-popover
Syncs the current open state with your parent vue instance. View the Info about v-model section for more details.
If modelValue
is set to true
, the popover will show. So you can open the popover programmatically while giving the user the option to close the popover by clicking outside of it.
Even if you use the popover as a tooltip that simply shows when the user hovers over an element, you still need to use v-model!
Name | Is also the default slot | Extra info |
---|---|---|
element |
No | The target element where the popover should be attached to |
content |
No | The content of the popover |
header |
No | Place elements in the header (OPTIONAL) |
Name | Type | Default | Extra info |
---|---|---|---|
modelValue |
Boolean | Required. Controls whether the popover is shown or not | |
type |
String | match |
Color type of popover. Either match or contrast (= dark bg-color if lightmode is active) |
zIndex |
Number | 10 |
Z-Index of popover element |
hover |
Boolean | false |
If true , the popover will show if the user hovers over the target element |
hoverDelay |
Number | 700 |
In MS. Delay to wait before popover will show (only for hover). Aborts if user stops hovering over target element |
hideOnClickOutside |
Boolean | true |
If the user clicks outside, the popover will hide |
minWidth |
String | 0 |
Desired css min-width value, e.g. "400px"
|
maxWidth |
String | unset |
Desired css max-width value, e.g. "600px"
|
maxHeight |
String | unset |
Desired css max-height value, e.g. "100px"
|
placement |
String | bottom |
See Popper options |
offsetY |
Number | 15 |
Y-Offset of popover |
offsetX |
Number | 0 |
X-Offset of popover |
headline |
String | null |
|
description |
String | null |
<hy-popover v-model="popover.isOpen" minWidth="400px" headline="Headline" description="Description">
<template #element>
<hy-button v-on:click="popover.isOpen = !popover.isOpen">Toggle popover</hy-button>
</template>
<template #header>
<hy-button size="light"> ... </hy-button>
</template>
<template #content>
<h4>Hello World</h4>
<hy-input v-model="testInput"/>
</template>
</hy-popover>
A popover container. Floats above the main content and stays attached to the target element with the help of Popper. Will disappear if the user clicks outside of it.
Does NOT support hover
.
HyPopover was designed to be used "inline" with one element.
If you want to have one popover component and be able to attach it to different elements, then please use this component.
A popover may require a lot of computing resources. Use HyPopoverFree in dynamic situations (e.g. when using v-for): one HyPopoverFree that may attach to different elements depending on the situation.
hy-popover-free
Syncs the current open state with your parent vue instance. View the Info about v-model section for more details.
If modelValue
is set to true
, the popover will show. So you can open the popover programmatically while giving the user the option to close the popover by clicking outside of it.
Name | Is also the default slot | Extra info |
---|---|---|
content |
Yes | The content of the popover |
header |
No | Place elements in the header (OPTIONAL) |
Name | Type | Default | Extra info |
---|---|---|---|
modelValue |
Boolean | Required. Controls whether the popover is shown or not | |
element |
HTMLElement | null |
Required. Target element to which the popover should attach to. If changed, the popover will attach to the new element |
type |
String | "match" |
Color type of popover. Either match or contrast (= dark bg-color if lightmode is active) |
zIndex |
Number | 10 |
Z-Index of popover element |
hideOnClickOutside |
Boolean | true |
If the user clicks outside, the popover will hide |
minWidth |
String | 0 |
Desired css min-width value, e.g. "400px"
|
maxWidth |
String | unset |
Desired css max-width value, e.g. "600px"
|
maxHeight |
String | unset |
Desired css max-height value, e.g. "100px"
|
placement |
String | "bottom" |
See Popper options |
offsetY |
Number | 15 |
Y-Offset of popover |
offsetX |
Number | 0 |
X-Offset of popover |
headline |
String | null |
|
description |
String | null |
Vue template:
<hy-popover-free v-model="myPopover.isOpen" :element="myPopover.targetElement" headline="Headline" description="Description">
<p>Popover</p>
</hy-popover-free>
<!-- Just some example elements the popover can attach to -->
<!-- We use pointer-events: none on the icons to prevent the popover from attaching to the icon instead of the button -->
<hy-flex-container>
<hy-button @click="openPopover($event.target)"> <i class="icon-printer" style="pointer-events: none"></i> </hy-button>
<hy-button @click="openPopover($event.target)"> <i class="icon-image" style="pointer-events: none"></i> </hy-button>
<hy-button @click="openPopover($event.target)"> <i class="icon-megaphone" style="pointer-events: none"></i> </hy-button>
<hy-button @click="openPopover($event.target)"> <i class="icon-calendar" style="pointer-events: none"></i> </hy-button>
<hy-button @click="openPopover($event.target)"> <i class="icon-home" style="pointer-events: none"></i> </hy-button>
<hy-button @click="openPopover($event.target)"> <i class="icon-lock-open" style="pointer-events: none"></i> </hy-button>
</hy-flex-container>
Within your Vue instance:
data() {
return {
myPopover: {
targetElement: null,
isOpen: false,
}
}
},
methods: {
openPopover(targetElement) {
this.myPopover.targetElement = targetElement;
// Sometimes, using vue's $nextTick is required. See Known Issues for more detail.
this.$nextTick(() => {
this.myPopover.isOpen = true;
}
},
},
If you receive this error:
HyperUI Error: Target element found but not yet rendered. Please try wrapping code updating the modelValue in this.$nextTick()
Then wrapping the code responsible for updating the modelValue in this.$nextTick()
might help:
function openMyPopover(el) {
// Setting the target element
this.myPopoverFree.element = el;
// Open popover
this.$nextTick(() => {
this.myPopoverFree.open = true;
});
}
Sometimes a modal is just right for mobile devices but too big on desktops. A smart menu is a modal on mobile that turns into a compact popover on desktop. This components uses HyModal and HyPopover under the hood.
As smart menus use popovers, they may require a lot of computing resources. We recommend not using too many of them, certainly not in dynamic scenarios (e.g. using v-for).
In dynamic scenarios, HySmartMenuFree might work better.
hy-smart-menu
Syncs the current open state with your parent vue instance. View the Info about v-model section for more details.
If modelValue
is set to true
, the menu will show.
Name | Is also the default slot | Extra info |
---|---|---|
element |
No | The element to attach the popover to |
content |
No | The content of the popover / modal. A menuType variable is exposed to this slot. Read more about so called Scoped Slots
|
header |
No | Place elements in the header (Modal: next to the close button). Use size="light" to match the close button. (OPTIONAL) |
Name | Type | Default | Extra info |
---|---|---|---|
modelValue |
Boolean | Required. Controls whether the menu is shown or not |
Additionally, this menu supports these properties from HyModal (if mobile device):
background
, hideScrollbars
, doBSL
, disableSwipeToClose
, disableDismiss
, forceFullHeightOnMobile
, doBlurBg
, headline
, description
Additionally, this menu supports these properties from HyPopover (if desktop device):
hideOnClickOutside
, minWidth
, maxWidth
, maxHeight
, type
, placement
, offsetY
, offsetX
, headline
, description
<!-- Use properties from both HyPopover and HyModal -->
<hy-smart-menu v-model="mySmartMenu.isOpen" maxWidth="400px" background="#000" headline="Headline" description="Description">
<template #element>
<hy-button @click="mySmartMenu.isOpen = !mySmartMenu.isOpen">Toggle smart menu</hy-button>
</template>
<template #header>
<hy-button size="light"> ... </hy-button>
</template>
<template #content>
<p>A smart menu is a modal on mobile that turns into a compact popover on desktop.</p>
<hy-button @click="mySmartMenu.isOpen = false" type="primary">Close this smart menu</hy-button>
</template>
</hy-smart-menu>
Access the menuType
variable exposed to the slot:
<!-- Notice the syntax for a named scoped slot. Refer to the vue docs for more info. -->
<template #content="{ menuType }">
<p>{{ menuType }}</p>
</template>
A smart menu using HyPopoverFree, which may be better suited in dynamic situations.
This components uses HyModal and HyPopoverFree under the hood.
For docs, please refer to HySmartMenu and look into HyPopoverFree for troubleshooting.
As smart menus use popovers, they may require a lot of computing resources. We recommend not using too many of them. But this component, HySmartMenuFree, uses HyPopoverFree under the hood so it can be attached dynamically.
hy-smart-menu-free
Name | Is also the default slot | Extra info |
---|---|---|
content |
Yes | The content of the popover / modal. A menuType variable is exposed to this slot. Read more about so called Scoped Slots
|
header |
No | Place elements in the header (Modal: next to the close button). Use size="light" to match the close button. (OPTIONAL) |
Additional to the options posted in HySmartMenu, this component inherits the element
option from HyPopoverFree.
<hy-smart-menu-free v-model="mySmartMenu.isOpen" :element="mySmartMenu.targetElement">
<p>Hello World</p>
</hy-smart-menu-free>
Attention: Accessing menuType
is different if using only the default ('content') slot:
<!-- Notice the syntax for this scoped slot as well as the position compared to a regular HySmartMenu. Refer to the vue docs for more info -->
<hy-smart-menu-free v-slot="{ menuType }">
<p>{{ menuType }}</p>
</hy-smart-menu-free>
If you want to also place elements in the header:
<hy-smart-menu-free v-slot="{ menuType }">
<template #element>
<hy-button @click="mySmartMenu.isOpen = !mySmartMenu.isOpen">Toggle smart menu</hy-button>
</template>
<template #header>
<hy-button size="light"> ... </hy-button>
</template>
<template #content="{ menuType }">
<p>A smart menu is a modal on mobile that turns into a compact popover on desktop.</p>
<hy-button @click="mySmartMenu.isOpen = false" type="primary">Close this smart menu</hy-button>
</template>
</hy-smart-menu-free>
An iOS style list icon. Best used within sections with automatic dividers turned on to create an elegant e.g. settings page.
hy-list-icon
Pass your icon into the default slot.
Name | Type | Default | Extra info |
---|---|---|---|
color |
String | "transparent" |
Background color. Use blue , pink , orange , green , red , light-blue or purple . The font/icon color will be adjusted automatically to fit the background. |
<hy-list-icon color="light-blue">
<i class="icon-printer"></i> <!-- Your icon -->
</hy-list-icon>
Best used in sections:
<hy-section :dividers="true">
<hy-flex-container :allowBreak="false">
<hy-list-icon color="pink"> <i class="icon-printer"></i> </hy-list-icon>
<hy-toggle type="right"> Toggle this </hy-toggle>
</hy-flex-container>
<hy-flex-container :allowBreak="false">
<hy-list-icon color="orange"> <i class="icon-plus-circle"></i> </hy-list-icon>
<p>Look at this</p>
</hy-flex-container>
</hy-section>
A header component. Sticks to the top of the screen on mobile and floats on desktop devices.
The following steps need be performed if using this component:
-
We recommend using the same values for the properties
maxHeight
andresizeTo
as used on HyMain -
We recommend using the same value for the property
switchToMobileAt
as used on HyNavigationContainer -
Always place the header ABOVE the HyMain component
-
Put this in your HTML head:
<meta name="theme-color" content="#fff" media="(prefers-color-scheme: light)" /> <meta name="theme-color" content="hsl(220, 5%, 13%)" media="(prefers-color-scheme: dark)" />
If you need any guidance on how to structure your code, take a look at this guide: Recommended navigation code structure
hy-header
Name | Is also the default slot | Extra info |
---|---|---|
left |
Yes | Position: left, next to headline |
right |
No | Position: far right |
Name | Type | Default | Extra info |
---|---|---|---|
headline |
String | null |
|
icon |
String | null |
Name of an icon to display left of headline. Uses an <i class="..." />
|
doCoverShadow |
Boolean | true |
Adds a shadow underneath. Lets elements scrolling underneath fade into the void |
floating |
Boolean | true |
Do floating look on desktop devices |
extendHeadline |
Boolean | true |
Controls .hy-extend-full class on headline element |
maxWidth |
String | 1400px |
Must be same value as corresponding property on HyMain |
resizeTo |
Number | 95 |
Must be same value as corresponding property on HyMain |
switchToMobileAt |
Number | 850 |
Must be same value as corresponding property on HyNavigationContainer |
zIndex |
Number | 200 |
<hy-header maxWidth="800px" :resizeTo="90" headline="HyperUI" icon="icon-home">
<!-- Any additional elements go here -->
</hy-header>
More complex example with two slots
<hy-header maxWidth="800px" :resizeTo="90" headline="HyperUI" icon="icon-home">
<!-- Left slot must be named explicitly -->
<template #left>
<hy-button type="transparent-bg" size="thin">
<i class="icon-chevron-left"></i> Back
</hy-button>
</template>
<!-- Right slot can be treated as the default slot, but can named explicitly -->
<hy-button type="primary" size="thin"> Hello </hy-button>
</hy-header>
A component that can hold multiple sections which can be resized with a drag handle.
It's like a flex container with drag handles :)
hy-split-view
Just pass as many elements/sections you want. There is no maximum sections limit.
BUT, you must give each section an individual name. Which name you choose is up to you. Read more about named slots.
Name | Type | Default | Extra info |
---|---|---|---|
minSizes |
Array | null |
Specify minimum widths for each section. Use px or % values. Use null to allow the section to fully collapse. |
maxSizes |
Array | null |
Specify maximum widths for each section. Use px or % values. Use null to allow the section to fully expand and take all the available space. |
initialSizes |
Array | null |
Specify initial widths for each section. Use px or % values. Use null to let it the component distribute the remaining space for each section. |
direction |
String | row |
row or column . If choosing column , please assign an explicit height to the component. Otherwise every section will just be as small as possible and the component will not be interactable. |
handleType |
String | normal |
normal , normal-transparent or slim
|
disabled |
Boolean | false |
|
doBSL |
Boolean | true |
This component automatically locks body scrolling (BSL) while dragging |
<hy-split-view :minSizes="['30px', null, '10%']" :maxSizes="['50%', null, null]" :initialSizes="['40%', null, null]" direction="row" handleType="slim" :disabled="disabledVariable" style="height: 400px"> <!-- Explicit height required, as direction="column" would otherwise be relatively useless -->
<!-- Min width: 30px -->
<!-- Max width: 50% -->
<!-- Initial width: 40% -->
<template #slot1>
<hy-section style="height: 100%">
<p>Content of slot 1</p>
</hy-section>
</template>
<!-- Min width: 0px -->
<!-- Max width: 100% (in reality less, since the first slot has a min-width constraint) -->
<!-- Initial width: 30% (automatically calculated) -->
<template #slot2>
<hy-section style="height: 100%">
<p>Content of slot 2</p>
</hy-section>
</template>
<!-- Min width: 10% -->
<!-- Max width: 100% (in reality less, since the first slot has a min-width constraint) -->
<!-- Initial width: 30% (automatically calculated) -->
<template #slot3>
<hy-section style="height: 100%">
<p>Content of slot 3</p>
</hy-section>
</template>
</hy-split-view>
Note: what you put inside the templates is completely up to you. We just added the height: 100%
to make all the sections fill the entire available space within one column.
This is not a component but rather a utility class.
To activate, apply to any element the class hy-floating-badge
.
Now you may specify the text to display via an data-badge-text
attribute.
You may use v-bind:data-badge-text
to bind the attribute to a reactive vue variable (see example 2). This attribute can be ommited (or fed an empty string) to just show a small dot above the target element (see example 3).
Example 1:
<hy-button class="hy-floating-badge" data-badge-text="10k">Show the News</hy-button>
Example 2:
<hy-button class="hy-floating-badge" v-bind:data-badge-text="myBadgeText">Show the News</hy-button>
<hy-input v-model="myBadgeText" placeholder="Badge text"></hy-input>
Example 3:
<hy-button class="hy-floating-badge">Show the News</hy-button>
Every component has a class for easy css targeting. These classes are specified in the Component Documentation under Targeting class
.
The library puts certain styles on text elements like p
or h1
tags. You can disable this by adding class="hy-reset"
to that specific element.
Applies flex: 100 !important
to an element. Useful in a <hy-flex-container>
if all other elements should shrink to their minimal size.
See this example:
<hy-flex-container>
<h3 class="hy-extend-full">My element</h3>
<hy-button>Do action</hy-button>
</hy-flex-container>
On desktop, the button
will shrink automatically to it's minimal size to give the h3
room.
On mobile, these elements will be arranged beneath each other automatically, both having the same size and without one element being weirdly shaped or having the wrong width.
Removes the top-margin from the first child and the bottom-margin from the last child.
Ever noticed the Section
or Popover
components doing exactly this?
Removes the top-margin from the first child.
Removes the bottom-margin from the last child.
This removes margins (and paddings).
Removes the distance between itself and the element beneath it. Also makes the space between itself and the previous element bigger. Can only be used on p
-Tags!
Just adds a shadow, like a button has.
Build for increasing contrast if working with sections. (But it works on any component). If you want this to be default for every section, then add these lines of code to your css:
.hy-section {
box-shadow: var(--section-shadow);
}
Changes font color of the element and all its childs. Available classes are:
hy-text-accent
hy-text-blue
hy-text-pink
hy-text-yellow
hy-text-green
hy-text-red
hy-text-light-blue
hy-text-purple
hy-text-accent
hy-text-gray-1
hy-text-gray-2
hy-text-gray-3
hy-text-gray
Applies a border color of the accent color (border-color: var(--accent-color)
) to the element and all its top level childs.
Applies a font weight of bold to the element and all its level childs.
Applies a font weight of normal to the element and all its level childs.
Tries to hide scrollbars of that element.
Instantly apply a background-color for an element from your html. Available classes are:
hy-bg-blue
hy-bg-pink
hy-bg-yellow
hy-bg-green
hy-bg-red
hy-bg-light-blue
hy-bg-purple
hy-bg-accent
hy-bg-gray-1
hy-bg-gray-2
hy-bg-gray-3
View documentation here.
--font-size: 20px;
--font-size-small: calc(var(--font-size) * 0.75);
--font-family: Helvetica, sans-serif;
--flex-gap: 10px;
--section-padding: 1rem;
--section-border-radius: calc(2 * var(--element-border-radius));
--section-shadow: 0 0 32px 5px var(--section-shadow-color);
--section-divider: 2px solid var(--section-divider-color);
--element-border-secondary: 2px solid var(--element-border-secondary-color);
--element-border-accent: 2px solid var(--accent-color);
--element-border-error: 2px solid var(--color-pink);
--element-margin-value: 0.9rem;
--element-margin: var(--element-margin-value) 0;
--element-padding: 0.75rem;
--element-padding-light: 0.5rem;
--element-padding-thin: 0.25rem;
--element-transition: none 0.2s ease-in-out;
--element-shadow: 0px 4px 8px -2px var(--element-shadow-color);
--element-border-radius: 0.5rem;
--popover-shadow: 0 0 32px 15px var(--popover-shadow-color);
--dropdown-top-shadow: 0px 0px 8px 2px var(--element-shadow-color); // If dropdown expands to the top, the dividing shadow must also spread to the top
// Navigation
--tabbar-shadow: 0 0 25px 5px var(--tabbar-shadow-color);
--sidebar-shadow: 0 0 25px 5px var(--sidebar-shadow-color);
--header-shadow-cover: 0px 0px 18px 15px var(--body-bg-color);
(if device width is smaller than 600px)
--font-size: 18px;
--element-padding: 0.72rem;
--section-padding: 1rem;
--font-color-white: white;
--font-color-black: hsl(210, 29%, 24%);
--font-color-contrast: var(--font-color-black); // Default in light theme => "Contrast" to the background color
--font-color-match: var(--font-color-white);
// DEPRECATED => Use "contrast" / "match" colors instead
--font-color-dark: var(--font-color-contrast);
--font-color-bright: var(--font-color-match);
// General
--body-bg-color: hsl(240, 13%, 94%);
--accent-color: var(--color-blue);
--loader-ring-bg-color: hsl(0, 0%, 87%);
// Theme Colors
--color-blue: hsl(222, 100%, 61%);
--color-pink: hsl(340, 82%, 49%);
--color-yellow: hsl(44, 97%, 50%);
--color-green: hsl(116, 45%, 54%);
--color-red: hsl(0, 76%, 58%);
--color-light-blue: hsl(205, 100%, 62%);
--color-purple: hsl(321, 62%, 46%);
--color-gray-font: hsl(208, 7%, 46%);
--color-gray-1: hsl(210, 14%, 89%);
--color-gray-2: hsl(210, 16%, 93%);
--color-gray-3: hsl(210, 17%, 97.5%);
// Sections: Colors
--section-shadow-color: hsla(0, 0%, 41%, 0.1);
--section-bg-color: white;
// Element: Primary Colors
--element-primary-bg-color: var(--accent-color);
--element-primary-hover-bg-color: hsl(222, 100%, 53%);
// Element: Secondary Colors
--element-secondary-bg-color: var(--section-bg-color);
--element-secondary-hover-bg-color: hsl(0, 0%, 96%);
--element-border-secondary-color: hsl(231, 9%, 84%);
// Element: Others
--element-shadow-color: hsla(0, 0%, 72%, 0.33);
--section-divider-color: hsl(0, 0%, 88%);
--gray-tabbar-bg-color: hsl(210, 17%, 96%);
--gray-tabbar-ghost-color: var(--section-bg-color);
// Button light colors
--button-transparent-bg: hsla(230, 11%, 85%, 0.145);
--button-transparent-hover: hsla(230, 11%, 72%, 0.145);
--button-light-blue-bg: hsla(214, 100%, 85%, 0.27);
--button-light-blue-hover: hsla(214, 100%, 70%, 0.27);
--button-light-blue-font: hsl(214, 85%, 50%);
--button-light-red-bg: hsla(0, 100%, 88%, 0.29);
--button-light-red-hover: hsla(0, 100%, 73%, 0.29);
--button-light-red-font: var(--color-pink);
--button-light-orange-bg: hsla(44, 100%, 87%, 0.53);
--button-light-orange-hover: hsla(44, 100%, 75%, 0.53);
--button-light-orange-font: hsl(44, 100%, 50%);
--button-light-green-bg: hsla(114, 100%, 82%, 0.22);
--button-light-green-hover: hsla(114, 100%, 52%, 0.22);
--button-light-green-font: hsl(115, 88%, 51%);
// Modal
--modal-bg-color: var(--section-bg-color);
--modal-cover-color-mobile: hsla(0, 0%, 26%, 0.6);
--modal-cover-color-desktop: hsla(0, 0%, 100%, 0.5);
--modal-shadow-color: hsla(0, 0%, 37%, 0.4);
// Popover
--popover-shadow-color: hsla(0, 0%, 41%, 0.17);
--popover-bg-color-match: var(--section-bg-color);
--popover-bg-color-contrast: hsl(220, 5%, 13%); // Darkmode section-bg-color
// Navigation
--tabbar-shadow-color: hsla(0, 0%, 81%, 0.56);
--sidebar-shadow-color: var(--tabbar-shadow-color);
--font-color-white: hsl(0, 0%, 80%);
--font-color-black: hsl(0, 0%, 20%);
--font-color-contrast: var(--font-color-white); // Default in dark theme => "Contrast" to the background color
--font-color-match: var(--font-color-black);
// DEPRECATED => Use "contrast" / "match" colors instead
--font-color-dark: var(--font-color-contrast);
--font-color-bright: var(--font-color-match);
// General
--body-bg-color: hsl(240, 9%, 5%);
--accent-color: var(--color-blue);
--loader-ring-bg-color: hsl(0, 0%, 20%);
// Theme Colors
--color-blue: hsl(222, 100%, 61%);
--color-pink: hsl(340, 82%, 49%);
--color-yellow: hsl(44, 97%, 50%);
--color-green: hsl(116, 45%, 54%);
--color-red: hsl(0, 76%, 58%);
--color-light-blue: hsl(205, 100%, 62%);
--color-purple: hsl(321, 62%, 46%);
--color-gray-font: hsl(208, 7%, 46%);
--color-gray-1: hsl(210, 9%, 31%);
--color-gray-2: hsl(210, 10%, 23%);
--color-gray-3: hsl(207, 11%, 9%);
// Sections: Colors
--section-shadow-color: hsla(0, 0%, 3%, 0.5);
--section-bg-color: hsl(210, 11%, 11%);
// Element: Primary Colors
--element-primary-bg-color: var(--accent-color);
--element-primary-hover-bg-color: hsl(222, 100%, 53%);
// Element: Secondary Colors
--element-secondary-bg-color: var(--section-bg-color);
--element-secondary-hover-bg-color: hsl(210, 11%, 10%);
--element-border-secondary-color: hsl(210, 11%, 23%);
// Element: Others
--element-shadow-color: hsla(0, 0%, 0%, 0.4);
--section-divider-color: hsl(0, 0%, 27%);
--gray-tabbar-bg-color: var(--color-gray-3);
--gray-tabbar-ghost-color: var(--color-gray-2);
// Button light colors
--button-transparent-bg: hsla(224, 9%, 30%, 0.15);
--button-transparent-hover: hsla(224, 9%, 30%, 0.25);
--button-light-blue-bg: hsla(214, 63%, 33%, 0.1);
--button-light-blue-hover: hsla(214, 63%, 53%, 0.15);
--button-light-blue-font: hsl(214, 65%, 61%);
--button-light-red-bg: hsla(0, 65%, 38%, 0.1);
--button-light-red-hover: hsla(0, 65%, 48%, 0.15);
--button-light-red-font: var(--color-pink);
--button-light-orange-bg: hsla(44, 78%, 16%, 0.3);
--button-light-orange-hover: hsla(44, 78%, 26%, 0.35);
--button-light-orange-font: hsl(44, 100%, 50%);
--button-light-green-bg: hsla(114, 51%, 49%, 0.1);
--button-light-green-hover: hsla(114, 100%, 50%, 0.15);
--button-light-green-font: hsl(115, 73%, 47%);
// Modal
--modal-bg-color: var(--section-bg-color);
--modal-cover-color-mobile: hsla(0, 0%, 0%, 0.85);
--modal-cover-color-desktop: hsla(0, 0%, 0%, 0.85);
--modal-shadow-color: hsl(0, 0%, 0%);
// Popover
--popover-shadow-color: hsla(0, 0%, 3%, 0.5);
--popover-bg-color-match: var(--section-bg-color);
--popover-bg-color-contrast: white; // Lightmode section-bg-color
// Navigation
--tabbar-shadow-color: hsla(0, 0%, 0%, 0.6);
--sidebar-shadow-color: var(--tabbar-shadow-color);
Sometimes it may be necessary to update the styles of a component. If you just want to re-style a section, that's easy. But it becomes more difficult if you are working with scoped css and want to update a child node of a component, e.g. the visual of a button.
First, we need to understand how some components are build. Many of them are nested inside a container which is responsible for tasks such as positioning elements or itself in a parent.
A child of this container would be the actual <button>
element (for example), which has default css properties like a background-color or a border-radius.
If you want to change these, but still continue working within scoped css, you will quickly realize that you are able to style the container (by selecting it with the correct class; see component docs), but not so easy the actual button.
To work around these issues, Vue proposes to using the :deep()
pseudo-class, or you can style the elements from a non-scoped css block.
<style scoped>
.hy-button :deep(button) {
background-color: yellow;
}
</style>
<style scoped>
/* Other styles */
</style>
<style>
.hy-button button {
background-color: yellow;
}
</style>
You may also need to make these rules !important
, depending on your selector specificity.
Often, components use v-model
. This directive allows these components to sync a state variable between the component and the parent Vue instance. You may want to read this introduction from the official Vue docs.
Essentially, v-model="someVariable"
is a shorthand for :modelValue="someVariable" @update:modelValue="newValue => someVariable = newValue"
.
So these two pieces of code do the same thing:
<hy-input v-model="someVariable" />
<hy-input :modelValue="someVariable" @update:modelValue="newValue => someVariable = newValue" />
This extended syntax allows for more customization, so you could, for example, call a method if the modelValue changes.
If you see a modelValue
attribute that is required in the docs for a HyperUI component, than this is just a fancy way of saying that this components needs a v-model
binding to do its job. Often we use v-model to sync an important state of an component, like whether the modal is open or not.
Currently, the size option supports normal
, light
and thin
. This option can be set individually for each element or via HyperUI config globally.
HyperUI is an opinionated UI library. We thus recommend the following code structure when setting up a navigation system with Vue Router:
In App.vue:
<hy-navigation-container>
<template #sidebar>
<hy-navigation-sidebar>
<!-- Sidebar content -->
</hy-navigation-sidebar>
</template>
<template #tabbar>
<hy-navigation-tabbar>
<!-- Tabbar content -->
</hy-navigation-tabbar>
</template>
<template #content>
<router-view></router-view>
</template>
</hy-navigation-container>
And then in every View:
<hy-header headline="Headline of this view" maxWidth="800px" :resizeTo="90">
<!-- Some buttons or whatever -->
</hy-header>
<hy-main maxWidth="800px" :resizeTo="90">
<!-- View content -->
</hy-main>
Using this structure is the intended way of using the navigation components HyperUI provides and ensures good looking alignment in regards to screen edges and other elements.
As you can see in the example, use the same values for the maxWidth
and resizeTo
properties on both the header and main component.
Component | Value | Can be changed with zIndex property |
---|---|---|
HyFloatingBadge |
10 | No |
HyCheckbox |
1 | No |
HyRadioButton |
1 | No |
HyToggle |
1 | No |
HyTabbar |
5 | No |
HyDropdown |
10 | Yes |
HyPopover |
10 | Yes |
HyPopoverFree |
10 | Yes |
HyModal |
100 | Yes |
HySmartMenu |
200 | Yes |
HySmartMenuFree |
200 | Yes |
HyHeader |
50 | Yes |
HyNavigationContainer > #sidebar |
101 | No |
HyNavigationSidebar |
101 | No |
HyNavigationTabbar |
100 | No |
Nearly all sizes/paddings/margins etc. in HyperUI are derived from the --font-size
css custom property. If you want to scale down/up the UI, then simply change this property.
On mobile, the --font-size
is automatically decreased by the library. If you wish so, you may also overwrite this.
Look into CSS Variables for reference.
Some components not only support one slot, but multiple. Look for the Slots
section in the component documentation for an overview about which slots your component supports.
When planning to use multiple slots, named slots come into play. Please read this article about what these are.
In short:
- Use the
<template #nameOfSlot> ... </template>
syntax to address named slots - Sometimes, a slot is also aliased as the "default slot"
- If you just want to use the default slot, you don't need to use the
<template #nameOfSlot> ...
syntax - Once you want to fill multiple slots, then also the default slot has to use the
<template #nameOfSlot> ...
syntax - If a component just has one slot, then it is always aliased as the default slot -> you can use it without the
<template #nameOfSlot> ...
syntax
- Navigation Sidebar
- Redesign
- Collapsable
- Sidebar now supports mobile
- Added invalid option to Select, SelectDropdown, Dropdown and TextArea
- Header: refactored aligment -> new options and no longer dependent on HyMain
- Modal: new
header
slot - Dropdown: new
title
slot as an alternative to the prop - All Popovers, all SmartMenus
- the
menu
/popover
slots have been renamed tocontent
- added support for
headline
anddescription
prop andheader
slot
- the
- Added resizable split view component
- Added dropdown component
- Added dropdown-select component as an alternative style to the hy-select component
- Input: Support for showing an invalid state
- Header: Added a second "left" slot
- Modal: Added blur background (
doBlurBg
property) - Modal: Added
headline
anddescription
property - Tabbar: added new design option
- Updated color scheme
- Added
--color-gray-font
property and.hy-text-gray
class as an alternative tocolor: gray
- Bugfixes
- HyperUI now automatically adds the
hy-modals-container
andhy-popovers-container
to the DOM. You may now remove them from your codebase.
- Added
hy-smart-menu
andhy-smart-menu-free
as a compromise between a modal and a popover - Added
hy-header
component - Added
hy-progress-bar
component - Added
size
option to Button, Input and Select components - Added new
light-bg
type options for Button component - Section now also supports
title
,pre
andpost
- Section and Sub-Sections can now be collapsed
- Redesigned
hy-table
- Added option to show a progress bar instead of a loading spinner on supported components
Attention: we changed the target classes of elements to reflect new naming scheme -> See Breaking Changes for additional updates
- Added Free-Floating
hy-popover-free
as an alternative to the fixedhy-popover
. This component can be attached to multiple target elements - Ff a device supports touch events, modals can now be closed by swiping
- Darkmode: Primaries now use the blue accent color
- Added
maxWidth
andmaxHeight
property to popovers - Added
.hy-remove-leading-margins
utility class - Added
.hy-remove-trailing-margins
utility class
- Redesign modal for desktop devices
- Added navigation related components:
- Added NavigationContainer component, that switches between a tabbar and a sidebar
- Added NavigationSidebar component
- Added NavigationTabbar component
- Added a toggle "checkbox" component
- Added an iOS inspired ListIcon component
- Tweaked background-color of transparent buttons
- Tweaked darkmode colors
- Added
hy-extend-full
utility class - Added
hy-text-[COLOR]
utility classes - Added icons for Input fields and Selects
-
--font-color-dark
&--font-color-bright
are DEPRECATED, use--font-color-contrast
andfont-color-similar
instead - Added
.hy-remove-leading-trailing-margins
utility class
- Added dropzones for easier file reading and uploading
- Added radio buttons
- Added floating badges
- Renamed utility classes to include the
hy-
prefix. Old utility class names are DEPRECATED
- Renamed components to include the prefix "Hy"
- Attention: CSS variable names have changed
- Switched to a new bundler => You're required to import the styles for yourself
- New light and transparent colored button style
- Modals
- Popovers & Tooltips
- New sub-section component
- Inputs now support non-string values. But, it may still return a string if the user changes the value
- Checkboxes now have a right aligned mode
- Select between "light" and "dark" theme, or just use both of them automatically with config value "system"
- Docs for CSS variables
- Adjusted theme colors
- Section Border Radius CSS variable
-
.section-shadow
utility class - Docs for
:deep()
pseudo-class in re-style components - Bugfixes
- Color theme updates:
- New Dark Blue instead of Black
- New Accent Color is based on a red color (Light- & Darkmode)
- Buttons will have a default
font-weight
ofbold
- New
.fontWeightNormal
utility class. Reverts the previously noticed changes to afont-weight
ofnormal
. - New
.fontWeightBold
utility class. - New
.borderAccent
utility class. Turns the border color of a button (or a similar element) into the accent color.
- Added TextAreas
- Buttons got a new, transparent Style
- New
.textAccent
utility class for easily changing the text color to the accent color. Developed for being used with the new Button Style - Use Vue
$attrs
for Inputs & Texareas (more info in the component docs)
- Flex: Use
gap
property withing flex-containers - Flex: Removed the generic 5px margin
- Attention: Safari has been supporting the gap property since May 2021 which means not a lot of people have received the update yet. Consider waiting to update this library!
- Added a tabbar
- Elements get smaller on mobile screens
- Button: New accent-color style
- Updated accent colors to orange colors
- Switched colors for section and body background in darkmode