Squishy and soft UI components for React. Made with love and care.
Designed using Sass, Framer, FontAwesome and more.
Welcome to Mochi UI: A visionary library curated with a delightful blend of squishy, fluid design language, reminiscent of the mesmerizing Japanese rice cake it's named after.
Crafted entirely with pure CSS, Mochi UI redefines user interface design, offering a seamless fusion of aesthetics and functionality. Enriching the experience further, the library harnesses the power of Framer Motion to infuse animations with a mesmerizing fluidity.
Initially, Mochi UI was created as a set of components for a personal project. However, as the project grew, so did the need for a comprehensive library of components. Thus, Mochi UI was born.
The library is currently in its infancy, with only a handful of components available. However, the library will be updated regularly with new components and features. I hope you enjoy using Mochi UI as much as I enjoyed creating it.
npm i mochi-ui
To use the components, you need to import them from the package.
import { Button, Input } from 'mochi-ui';
Then you can use them in your code as shown in the examples below.
IMPORTANT: You need to add the "light" or "dark" class to the html tag.
<html class="light">
<Button
title='Click Me'
iconRight={<FontAwesomeIcon icon={faWandMagic} />}
onClick={() => {console.log('Click')}}
size='large'
color='primary'
/>
This is the text that will be displayed on the button.
The icon that is displayed on the left side of title
text. As this is a react component, you can pass in any react icon component you want.
The icon that is displayed on the right side of title
text. As this is a react component, you can pass in any react icon component you want.
The function that will be called when the button is clicked. If passed an async function, the button will be disabled until the function is resolved. While the function is running, the button will display a loading animation.
Boolean value that will make the button take up the full width of the container.
large | medium | small | icon
This is the size of the button. The default value is large
primary | secondary | tertiary | danger | warning
This is the color of the button. The default value is primary
. These colors can be changed by changing the css variables in your global css file.
This is a boolean value that will make the button have a shaded background.
This is a boolean value to remove the margin from the button. Set to true by default.
This is a boolean value that will make the button disabled.
<Input
domName='Name'
name='name'
value={name}
onChange={(e) => setName(e.target.value)}
placeholder='enter your name'
/>
This is the name that will be displayed on the label.
text | password | email | number | tel | search | week | textarea
This is the type of the input. The default value is text
.
This is the name that will be used to identify the input.
This is the value of the input. A react state.
This is the function that will be called when the value of the input changes.
This is the placeholder text that will be displayed when the input is empty.
This is the error message that will be displayed when the input is invalid. Only works when the touched
prop is set to true.
The boolean value that will be set to true when the input is touched.
This is a function that will be called when the input is touched.
This is a boolean value to disable the input.
<DatePicker
domName='Birthday'
name='birthday'
value={date}
onChange={(e) => setDate(e)}
/>
This is the name that will be displayed on the label.
This is the name that will be used to identify the input.
This is the value of the input. A react state.
This is the function that will be called when the value of the input changes.
This is a boolean value that will let you choose the time as well.
Set to true by default. This is a boolean value that will let you choose the date as well. Setting this to false will only let you choose the month.
This is the last year that will be displayed in the year dropdown.
This is the first year that will be displayed in the year dropdown.
This is the error message that will be displayed when the input is invalid. Only works when the touched
prop is set to true.
The boolean value that will be set to true when the input is touched.
This is a function that will be called when the input is touched.
This is a boolean value that will be set to true when the input is disabled.
<TimePicker
domName='Time'
name='time'
value={time}
onChange={(e) => setTime(e)}
/>
This is the name that will be displayed on the label.
This is the name that will be used to identify the input.
This is the value of the input. A react state.
This is the function that will be called when the value of the input changes.
This is the error message that will be displayed when the input is invalid. Only works when the touched
prop is set to true.
The boolean value that will be set to true when the input is touched.
This is a function that will be called when the input is touched.
This is a boolean value that will be set to true when the input is disabled.
<DropDown
domName='Favorite Food'
name='food'
value={food}
onChange={(e) => setFood(e)}
defaultValue='-- Choose your meal'
values={[
{
key: 'pizza',
label: 'Pizza 🍕',
},
{
key: 'burger',
label: 'Burger 🍔',
},
{
key: 'friedChicken',
label: 'Fried Chicken 🍗',
},
]}
unSelectable
/>
This is the name that will be displayed on the label.
This is the name that will be used to identify the input.
This is the value of the input. A react state.
This is an array of objects that will be displayed in the dropdown. Each object should have a key
and a label
.
This is the function that will be called when the value of the input changes.
This is the error message that will be displayed when the input is invalid. Only works when the touched
prop is set to true.
This is a boolean value that will be set to true when the input is touched.
This is a function that will be called when the input is touched.
This is the default value that will be displayed when the input is empty.
This is a boolean value that will make the value of the input unselectable.
This is a boolean value that will be set to true when the input is disabled.
<CheckBoxGroup
values={[
{
key: 'friedChicken',
label: 'Fried Chicken 🍗',
},
{
key: 'pizza',
label: 'Pizza 🍕',
},
{
key: 'dumplings',
label: 'Dumplings 🥟',
disabled: true,
},
{
key: 'tempura',
label: 'Tempura 🍤',
disabled: true,
},
]}
containerClassName={styles.checkBoxGroup}
value={foods}
onChange={(value) => setFoods(value)}
domName='What foods do you like?'
/>
This is the name that will be displayed on the label.
This is the name that will be used to identify the input.
This is the array of objects that will be displayed in the checkbox group. Each object should have a key
and a label
. The disabled
property is optional.
This is the value of the input. A react state. This is an array of strings.
This is the function that will be called when the value of the input changes. keys
is an array of strings.
This is the error message that will be displayed when the input is invalid. Only works when the touched
prop is set to true.
This is a boolean value that will be set to true when the input is touched.
This is a function that will be called when the input is touched.
This is the class name that will be applied to the container of the checkbox group. You can use this to style the checkbox group. A default style is applied if this prop is not passed.
This is the CheckBox component that is used in the CheckBoxGroup component. You can use it separately as well, but it is recommended that you use the CheckBoxGroup component.
<CheckBox
domName='Fried Chicken 🍗'
value={friedChicken}
onChange={() => setFriedChicken(!friedChicken)}
name='friedChicken'
/>
This is the name that will be displayed on the label.
This is the name that will be used to identify the input.
This is the value of the input. A react state.
This is the function that will be called when the value of the input changes.
A boolean value that will disable the checkbox.
<RadioGroup
values={[
{
key: 'friedChicken',
label: 'Fried Chicken 🍗',
},
{
key: 'pizza',
label: 'Pizza 🍕',
},
{
key: 'dumplings',
label: 'Dumplings 🥟',
},
{
key: 'tempura',
label: 'Tempura 🍤',
disabled: true,
},
]}
containerClassName={styles.checkBoxGroup}
value={radio}
onChange={(value) => setRadio(value)}
domName={`What's your favorite?`}
/>
This is the name that will be displayed on the label.
This is the name that will be used to identify the input.
This is the array of objects that will be displayed in the checkbox group. Each object should have a key
and a label
. The disabled
property is optional.
This is the value of the input. A react state.
This is the function that will be called when the value of the input changes.
This is the error message that will be displayed when the input is invalid. Only works when the touched
prop is set to true.
This is a boolean value that will be set to true when the input is touched.
This is a function that will be called when the input is touched.
This is the class name that will be applied to the container of the radio group. You can use this to style the radio group. A default style is applied if this prop is not passed.
This is the Radio component that is used in the RadioGroup component. You can use it separately as well, but it is recommended that you use the RadioGroup component.
<Radio
domName='Pizza 🍕'
value={pizza}
name='pizza'
onChange={() => setPizza(!pizza)}
/>
This is the name that will be displayed on the label.
This is the name that will be used to identify the input.
This is the value of the input. A react state.
This is the function that will be called when the value of the input changes.
A boolean value that will disable the checkbox.
You can customize the components by changing the css variables in your global css file. Here is an example of how you can do it. You can copy the code below and paste it in your global css file and change the colors to your heart's content.
html {
.mochiCustom {
--mainfont: 'Poppins' !important;
--light-e: #eeeeee !important;
--light-d: #dddddd !important;
--light-bg: #ffffff !important;
--dark-1: #111111 !important;
--dark-2: #222222 !important;
--dark-3: #333333 !important;
--dark-4: #444444 !important;
--dark-5: #555555 !important;
--dark-8: #888888 !important;
--secondary: #6ec2f7 !important;
--tertiary: #a686fc !important;
--danger: #ff7276 !important;
--warning: #fffaa0 !important;
--btn-color: var(--dark-3) !important;
--contrast-btn-color: var(--mainfont-color) !important;
--secondary-lighter: #6ec2f740 !important;
--tertiary-lighter: #a686fc40 !important;
--danger-lighter: #ff727640 !important;
--warning-lighter: #efcb6840 !important;
}
}
html.light {
.mochiCustom {
--primary: #7adc7a !important;
--primary-lighter: #7adc7a40 !important;
--background: var(--light-bg) !important;
--mainfont-color: var(--dark-3) !important;
--input-box: var(--light-e) !important;
--input-box-hover: var(--light-d) !important;
--menu-shadow: 0px 10px 15px -3px rgba(0, 0, 0, 0.2) !important;
}
}
html.dark {
.mochiCustom {
--primary: #9bfdcc !important;
--primary-lighter: #9bfdcc40 !important;
--background: var(--dark-1) !important;
--mainfont-color: var(--light-d) !important;
--input-box: var(--dark-2) !important;
--input-box-hover: var(--dark-3) !important;
--menu-shadow: 0px 10px 15px -3px rgba(0, 0, 0, 0.5) !important;
::placeholder {
color: var(--dark-8) !important;
}
}
}
.mochiCustom {
font-family: var(--mainfont) !important;
color: var(--mainfont-color) !important;
}
Here is an example of how you can use the components in your project. I have used Formik to handle the form state. Please see the code below the form for more details.
import React from 'react';
import {
Input,
DatePicker,
Button,
DropDown,
CheckBoxGroup,
} from 'mochi-ui';
import styles from './styles.module.scss';
import { AnimatePresence, motion } from 'framer-motion';
import { useFormik } from 'formik';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faArrowRight } from '@fortawesome/free-solid-svg-icons';
import * as yup from 'yup';
const schema = yup.object({
fname: yup
.string()
.required('First name is required')
.min(3, 'Min length is 3'),
dob: yup
.date()
.required('Date of birth is required')
.max(
new Date(
new Date(new Date().setFullYear(new Date().getFullYear() - 18)).setDate(
new Date().getDate() + 1
)
),
'You should be atleast 18 years old'
),
color: yup.string().required('Color is required'),
favoriteFood: yup
.array()
.required('Favorite food is required')
.min(1, 'Select atleast one food'),
});
function App() {
const [values, setValues] = React.useState();
const form = useFormik({
initialValues: {
fname: '',
dob: new Date(new Date().setFullYear(new Date().getFullYear() - 18)),
color: '',
favoriteFood: ['rice'],
},
validationSchema: schema,
onSubmit: async (values) => {
await dummyWait();
setValues(values);
},
});
async function dummyWait() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('done');
}, 1000);
});
}
return (
<div className={styles.box}>
<div className='normal'>
<h1 style={{ fontWeight: 500 }}>Sample Form</h1>
<div>
<Input
name='fname'
domName='First Name'
value={form.values.fname}
placeholder='enter your first name'
onChange={form.handleChange}
error={form.errors.fname}
touched={form.touched.fname}
setTouched={() => form.setFieldTouched('fname')}
/>
<DatePicker
domName='Your Birthday'
name='dob'
value={form.values.dob}
onChange={(date) => form.setFieldValue('dob', date)}
error={form.errors.dob}
touched={form.touched.dob}
setTouched={() => form.setFieldTouched('dob')}
endYear={new Date().getFullYear() - 18}
/>
<DropDown
domName='Favorite Color'
name='color'
value={form.values.color}
onChange={(value) => form.setFieldValue('color', value)}
// unSelectable={true}
values={[
{
key: 'r',
label: 'Red',
},
{ key: 'g', label: 'Green' },
{ key: 'b', label: 'Blue' },
]}
touched={form.touched.color}
setTouched={() => form.setFieldTouched('color')}
error={form.errors.color}
/>
<CheckBoxGroup
values={[
{
key: 'rice',
label: 'Rice',
disabled: true,
},
{
key: 'noodles',
label: 'Noodles',
},
{
key: 'hoppers',
label: 'Hoppers',
},
{
key: 'bread',
label: 'Bread',
},
]}
value={form.values.favoriteFood}
onChange={(value) => form.setFieldValue('favoriteFood', value)}
touched={form.touched.favoriteFood}
setTouched={() => form.setFieldTouched('favoriteFood')}
error={form.errors.favoriteFood}
domName='Favorite Food'
/>
</div>
<br />
<Button
title='Sign In'
iconRight={<FontAwesomeIcon icon={faArrowRight} />}
onClick={form.submitForm}
/>
<br />
<AnimatePresence>
<br />
{values && values.fname && (
<motion.div className={styles.result}>
<span>First Name: </span>
<span>{values.fname}</span>
<span>Date of Birth: </span>
<span>{values.dob.toISOString()}</span>
<span>Color: </span>
<span>{values.color}</span>
<span>Favorite Food: </span>
<span>{JSON.stringify(values.favoriteFood)}</span>
</motion.div>
)}
</AnimatePresence>
</div>
</div>
);
}
export default App;
I hope you found this library useful. If you have any suggestions or feedback, please feel free to contact me. You can reach out to me by filling the contact form at hasathcharu.com.Thank you for reading.