@fraserelliott/fe-utilities
v0.3.1
Published
Bootstrap-style CSS utilities prefixed with fe-, plus optional class presets and composition function.
Maintainers
Readme
fe-utilities
A small, Bootstrap-style CSS utility module using singular, composable classes - all safely prefixed with fe- to avoid conflicts with existing frameworks (Bootstrap, Tailwind, etc) and custom component styles.
This file is intentionally “boring and predictable”:
- one class = one job
!importantused consistently so utilities win when applied- spacing options provided in rem, em, and px
- flex utilities included for quick layout building
Compatibility note
This library is primarily developed and tested in a personal stack using Node, Vite, and React. It should work fine in other environments, but broader compatibility isn’t guaranteed yet - if you try it elsewhere and hit issues, feel free to open an issue on GitHub.
Why this exists
Sometimes you want the speed of utility classes without bringing in a full framework.
This file gives you the common stuff you reach for constantly:
- spacing (
padding/margin) - flex + alignment
- sizing helpers
- truncation
- a few accessibility helpers (like
sr-only)
The unit philosophy (important)
This module supports a simple rule:
rem= global layout spacing- scales with the site's root font size
- consistent across the entire UI (good for page rhythm)
em= component-internal spacing- scales with the component’s font size
- perfect for buttons, badges, cards, etc
px= “absolute nudge” spacing- use when you want fixed, exact spacing (icons, fine-tuning)
This keeps your spacing system consistent:
- the entire page scales together via
rem - individual components can scale themselves via
em
Installation
Option A: Simple CSS import
Put the file somewhere like:
src/styles/fe-utilities.css
Then import it:
Vite / React / modern bundlers
import "./styles/fe-utilities.css";Plain HTML
<link rel="stylesheet" href="/css/fe-utilities.css" />Option B: npm with css import
Install it in the command line:
npm i @fraserelliott/fe-utilitiesThen import it in a javascript file:
import "@fraserelliott/fe-utilities/fe-utilities.css";Option C: Install with npm (CSS + optional presets)
If you want to use the utility CSS and the optional JavaScript presets (pre-composed class strings), install via npm and import both.
1) Install
npm i @fraserelliott/fe-utilities2) Import the CSS (required for utilities)
In your app entry file (eg main.jsx / main.js):
import "@fraserelliott/fe-utilities/fe-utilities.css";3) Import presets (optional)
Presets give you reusable, pre-composed class names you can apply directly via className.
import { FEPresets } from "@fraserelliott/fe-utilities/presets";Example:
export function Example() {
return (
<div className={FEPresets.Card}>
<button className={FEPresets.Btn}>Click me</button>
</div>
);
}4) Optional: use the cx() helper
cx() is a small helper for composing class names cleanly.
It accepts:
- class strings
- preset/style functions
- conditional values (
condition && value)
import { cx } from "@fraserelliott/fe-utilities/cx";Example:
export function Example({ isPrimary }) {
return (
<button className={cx(FEPresets.Btn, isPrimary && "app-btn--primary")}>
Save
</button>
);
}Because presets are typically functions, you can also compose them semantically:
cx(FEPresets.Card, condition && FEPresets.Highlight);This keeps styling consistent while still allowing easy overrides.
Why presets?
The utility classes in fe-utilities.css are designed to be small and composable - but once you start building real UIs, you’ll often notice you’re repeatedly typing the same “bundles” of classes (eg a card layout, a button base, a flex row with consistent alignment).
That’s what presets solve.
Presets are pre-composed class strings you can reuse across your app:
- consistent layout and spacing without rethinking it every time
- fewer missing/forgotten utility classes
- faster UI building (especially when prototyping)
- easier to update a common pattern in one place later
Example:
import { FEPresets } from "@fraserelliott/fe-utilities/presets";
export function Example() {
return (
<div className={FEPresets.Card}>
<button className={FEPresets.Btn}>Save</button>
</div>
);
}Presets are intentionally optional - if you prefer writing raw utility classes directly in your markup, you can ignore them completely and just use the CSS file.
Project-specific presets (recommended)
The presets included with this package are meant to be a helpful starting point, not “the one true way”.
In most projects, you’ll quickly end up with your own app-specific variants (brand colours, button styles, layout rules, etc). A good pattern is to create a small file in your project that composes your own presets on top of the base FEPresets values.
cx supports both class strings and preset functions, so you can compose styles semantically while keeping overrides simple.
Example: src/styles/components.js
import { FEPresets } from "@fraserelliott/fe-utilities/presets";
import { cx } from "@fraserelliott/fe-utilities/cx";
export const UI = {
Card: (...extra) => cx(FEPresets.Card, ...extra),
Btn: (...extra) => cx(FEPresets.Btn, ...extra),
BtnPrimary: (...extra) => cx(FEPresets.Btn, "app-btn--primary", ...extra),
BtnSecondary: (...extra) => cx(FEPresets.Btn, "app-btn--secondary", ...extra),
};Usage:
import { UI } from "../styles/components";
export function Example() {
return (
<div className={UI.Card()}>
<button className={UI.BtnPrimary()}>Save</button>
<button className={UI.BtnSecondary()}>Cancel</button>
</div>
);
}Recommended usage notes
Presets are usually functions so you can easily apply small tweaks:
UI.Card("fec-opacity-80");cx()accepts both strings and preset functions:cx(UI.Card, condition && UI.Highlight);Avoid nesting
cx()calls - just pass additional arguments instead:cx(UI.Card, "extra-class", condition && UI.Highlight);
This keeps styling composable, predictable, and easy to override while letting each project define its own design language cleanly.
Naming conventions
All utilities are prefixed:
fe-...
Spacing naming
These follow the same patterns you’d expect from Bootstrap/Tailwind-ish utilities:
Rem-based spacing
fe-p-*/fe-m-*for padding/marginfe-px-*/fe-mx-*for left+rightfe-py-*/fe-my-*for top+bottomfe-pt-*,fe-pr-*,fe-pb-*,fe-pl-*fe-mt-*,fe-mr-*,fe-mb-*,fe-ml-*
Em-based spacing
fe-p-em-*fe-m-em-*
Px-based spacing
fe-p-px-*fe-m-px-*
Utility scale
Rem spacing scale
| Class | Value |
| ----- | --------- |
| *-0 | 0 |
| *-1 | 0.25rem |
| *-2 | 0.5rem |
| *-3 | 1rem |
| *-4 | 1.5rem |
| *-5 | 2rem |
Examples:
<div class="fe-p-3">...</div>
<div class="fe-mt-4">...</div>
<div class="fe-px-2 fe-py-1">...</div>Em spacing scale
| Class | Value |
| -------- | -------- |
| *-em-0 | 0 |
| *-em-1 | 0.25em |
| *-em-2 | 0.5em |
| *-em-3 | 1em |
| *-em-4 | 1.5em |
| *-em-5 | 2em |
Examples:
<button class="fe-p-em-2">Button</button>
<span class="fe-m-em-1">Inline spacing</span>Px spacing scale
| Class | Value |
| --------- | ------ |
| *-px-0 | 0px |
| *-px-4 | 4px |
| *-px-8 | 8px |
| *-px-12 | 12px |
| *-px-16 | 16px |
| *-px-24 | 24px |
Examples:
<div class="fe-p-px-8">...</div>
<div class="fe-m-px-16">...</div>Included utilities
Display
fe-d-nonefe-d-blockfe-d-inlinefe-d-inline-blockfe-d-flexfe-d-inline-flex
Flex direction + wrapping
fe-flex-rowfe-flex-columnfe-flex-row-reversefe-flex-column-reversefe-flex-wrapfe-flex-nowrap
Justify content
fe-justify-startfe-justify-centerfe-justify-endfe-justify-betweenfe-justify-aroundfe-justify-evenly
Align items
fe-items-startfe-items-centerfe-items-endfe-items-stretchfe-items-baseline
Align self
fe-self-startfe-self-centerfe-self-endfe-self-stretch
Flex grow/shrink
fe-grow-0fe-grow-1fe-shrink-0fe-shrink-1
Gap (rem-based)
fe-gap-0fe-gap-1fe-gap-2fe-gap-3fe-gap-4fe-gap-5
Examples:
<div class="fe-d-flex fe-gap-3">
<div>One</div>
<div>Two</div>
</div>Sizing
fe-w-100fe-h-100fe-w-autofe-h-autofe-min-w-0fe-min-h-0
✅
fe-min-w-0is especially useful inside flex containers to prevent overflow issues.
Text utilities
fe-text-leftfe-text-centerfe-text-rightfe-fw-normalfe-fw-boldfe-text-mutedfe-nowrapfe-break-wordfe-truncate
Example:
<div class="fe-truncate fe-min-w-0">
A long line that should not wrap and will ellipsis...
</div>Position utilities
fe-pos-relativefe-pos-absolutefe-pos-fixedfe-pos-sticky
Overflow utilities
fe-overflow-hiddenfe-overflow-autofe-overflow-x-autofe-overflow-y-auto
Border radius
fe-rounded-0fe-rounded-1fe-rounded-2fe-rounded-3fe-rounded-pill
Accessibility helpers
fe-sr-only
Example:
<button>
<span class="fe-sr-only">Close modal</span>
✕
</button>Animations / micro-interactions
fe-utilities includes a small set of optional animation helpers intended to add subtle “life” to interactive elements, without becoming distracting.
.fe-pressable (hover + press feedback)
Adds a slight lift on hover and a subtle “pressed in” scale on click/tap.
<button class="fe-pressable">Click me</button>
<a class="fe-pressable" href="#">Link</a>Notes:
- Works well on buttons, clickable cards, icon buttons, and links
- Includes a
:focus-visibleoutline for keyboard accessibility
.fe-anim-pulse (attention / CTA pulse)
A gentle pulse animation intended for temporary emphasis (eg “Next step” buttons).
<button class="fe-anim-pulse">Continue</button>Tip: Use this sparingly. If everything pulses, nothing feels important.
Reduced motion support
Animations and transitions are automatically disabled when the user has enabled reduced motion in their OS/browser settings:
prefers-reduced-motion: reduce
Example usage patterns
Card layout
<section class="fe-p-4 fe-d-flex fe-flex-column fe-gap-3">
<h2 class="fe-m-0">Title</h2>
<p class="fe-m-0 fe-text-muted">Body content goes here.</p>
<div class="fe-d-flex fe-justify-between fe-items-center fe-gap-3">
<button class="fe-p-em-2 fe-rounded-pill">Action</button>
<span class="fe-truncate fe-min-w-0">
A long secondary label that should truncate nicely...
</span>
</div>
</section>Simple horizontal toolbar
<div class="fe-d-flex fe-items-center fe-gap-2 fe-py-2 fe-px-3">
<button class="fe-p-em-2">Back</button>
<div class="fe-grow-1"></div>
<button class="fe-p-em-2">Save</button>
</div>Customising
Change the spacing scale
If you want this to behave like a design system, the best next step is turning it into a small SCSS generator so the spacing scale lives in one place.
If you want, you can also:
- add
fe-gap-em-*for component gaps - add
fe-border-*utilities - add
fe-shadow-*utilities - add
fe-color-*utilities (or keep colors as component styles)
Notes / limitations
- These utilities intentionally use
!importantso they behave predictably. - This is not intended to replace a full design system.
- The goal is speed + consistency + no naming collisions.
License
Use it however you like - this is a simple utility module intended for personal projects and portfolios.
