Skip to content

New400 animated icons, 75 free. See the icons ›

Nexus UI
Get Pro

ProPreview and play it free. Its code and sound come with Pro.

Animated Gas Pump icon for React.

A fuel pump whose display counts up as the hose twitches while it fills.

Use it forFuel price trackerTrip planner stopFind nearby stationsLow fuel warning

Plays while the pointer is on the stage. Drag it and let go.

Trigger
Mood
Look
Colour
Stage

What you hear. A metal nozzle clunk as the hose starts to move, a run of mechanical counter ticks that follows the display filling, rubbery hose slaps at each twitch, fuel rushing through, and a shut-off clunk when the display is full. Every note lands on a beat of the animation.

Use it

This is how you would use it. The file itself comes with Pro; the snippet follows everything you change on the stage.

TSXpage.tsx
import { GasPumpIcon } from "@/components/icons/gas-pump";
 
export default function Page() {
return (
<GasPumpIcon size={104} accent="#ff375f" />
);
}

Spark just sets the accent prop, so the small details of each icon get their own colour.

Where to use the gas pump icon

4 real places it fits, each one live. Hover, tap or press a key on a mock-up to see the icon move in context, then copy the file above and drop it in.

  • Fuel price tracker

    The display counts up on a station card in a fuel price app.

  • Trip planner stop

    A refuel suggestion row in a road trip planner.

  • Find nearby stations

    A search button on a maps home screen.

  • Low fuelNext station is 6 km away.

    Low fuel warning

    A dashboard alert in a connected car app.

More in context on the Made for real interfaces page: a player, a cart, a toolbar, a chat box and a tab bar.

The code

One file. Save it as components/icons/gas-pump.tsx, run npm i framer-motion, and import GasPumpIcon.

The Gas Pump code is part of Pro

Preview and play it above, with its looks and its sound. Pro unlocks the file to copy for every Pro icon.

See plans

The sound (optional)

A metal nozzle clunk as the hose starts to move, a run of mechanical counter ticks that follows the display filling, rubbery hose slaps at each twitch, fuel rushing through, and a shut-off clunk when the display is full. It is written against this icon's own animation: each line below is a note placed on a beat of the picture, and t() stretches it with the speed prop. There are no audio files: it is synthesised in the browser.

  1. Once per project, copy sound-engine.ts and sound-kit.ts from the sound guide into components/icons/.
  2. Save the score below as components/icons/sounds/gas-pump.ts.
  3. Call playIconScore(gasPump) from a click or hover handler:
"use client";
 
import { GasPumpIcon } from "@/components/icons/gas-pump";
import * as gasPump from "@/components/icons/sounds/gas-pump";
import { playIconScore } from "@/components/icons/sound-engine";
 
export function GasPumpButton() {
return (
<button
type="button"
onPointerEnter={() => playIconScore(gasPump)}
onClick={() => playIconScore(gasPump)}
>
<GasPumpIcon size={24} />
</button>
);
}

The Gas Pump sound is part of Pro

Preview and play it above, with its looks and its sound. Pro unlocks the score to play for every Pro icon.

See plans

Props

PropTypeDefaultWhat it does
sizenumber24Width and height in pixels.
strokeWidthnumber2Line thickness, in a drawing that is 24 units wide.
speednumber1Playback speed: 1 is the designed pace, 2 is twice as fast, 0.5 is half.
accentstringcurrentColorColour of the icon's small accent details (a badge, a spark, a trail). Left out, they match the icon.
classNamestring–Set a text colour here: the icon draws in currentColor.
playboolean–true plays, false rests. Left out, it follows the pointer (or loops, for loaders).

Looks (optional)

Wrap an icon, or a whole grid of them, in IconMaterial to give it a finish: neon glow, an aurora spectrum, polished chrome, or one of the liquid looks (Mercury, Liquid and Glass), which are pure SVG with no canvas or WebGL and each make a sound of their own. Save it as components/icons/icon-material.tsx. Spark needs no helper: it is just the accent prop.

"use client";
 
import { useId, type CSSProperties, type ReactNode } from "react";
import { useReducedMotion } from "framer-motion";
 
export type IconMaterialName = "line" | "spark" | "neon" | "aurora" | "chrome" | "mercury" | "liquid" | "glass";
 
/**
* Looks for the icons: wrap one icon, or a whole grid of them, and they all take on the same finish.
*
* line plain strokes in the current colour (the default; nothing is added)
* spark strokes in the current colour, with each icon's small accent details in colour:
* give the icons an `accent`, e.g. <BellIcon accent="#ff3b30" />
* neon a glow around every stroke, in the current colour
* aurora every stroke painted with a blue-to-orange spectrum
* chrome every stroke painted as polished metal (looks best on a dark background)
* mercury liquid metal: the strokes round and thicken into a lit tube, and a reflected room of light and
* dark bands flows slowly along them (best on a dark background)
* liquid the strokes in the current colour as a wet droplet: where they touch they melt together, with a
* glossy highlight, and the whole icon wobbles like jelly while the pointer is over it
* glass clear glass: a translucent body with a bright edge, a fringe of red and blue where the lens bends
* the light, and a sheen that drifts across (best on a dark or colourful background)
*
* It only restyles, so it works with any icon that draws in currentColor and has a 24-unit viewBox. The three
* liquid looks are pure SVG (gradients and filters): no canvas, no WebGL, nothing to load, and they hold still
* for visitors who have reduced motion switched on.
*/
 
const AURORA: [string, string][] = [["0", "#0090f7"], ["0.3", "#6e5bff"], ["0.55", "#ba62fc"], ["0.78", "#f2416b"], ["1", "#f55600"]];
const CHROME: [string, string][] = [["0", "#f4f5fb"], ["0.22", "#9ea3b6"], ["0.38", "#ffffff"], ["0.55", "#6d7183"], ["0.72", "#e8e9f2"], ["0.84", "#ffe3b8"], ["1", "#bfc3d4"]];
// The room mercury reflects, as one stripe of light: bright sky, soft grey, two hard dark bands and a warm window.
// It starts and ends on the same colour so it can repeat and flow without a seam.
const MERCURY: [string, string][] = [
["0", "#f6f7fc"], ["0.12", "#d6d9e8"], ["0.26", "#8e93aa"], ["0.32", "#262833"], ["0.4", "#a4a9bf"], ["0.52", "#ffffff"],
["0.6", "#646a80"], ["0.65", "#1c1e27"], ["0.73", "#cdd1e3"], ["0.85", "#ffe8c0"], ["1", "#f6f7fc"],
];
const GLASS: [string, string, number][] = [["0", "#ffffff", 0.95], ["0.35", "#e6f0ff", 0.55], ["0.7", "#cfe0ff", 0.3], ["1", "#ffffff", 0.7]];
 
export function IconMaterial({
material = "line",
color,
className,
style,
children,
}: {
material?: IconMaterialName;
/** The current colour for everything inside. Left out, it inherits. */
color?: string;
className?: string;
style?: CSSProperties;
children: ReactNode;
}) {
const uid = useId().replace(/[^a-zA-Z0-9_-]/g, "");
const scope = `nx-mat-${uid}`;
const reduce = useReducedMotion();
const flat = material === "aurora" || material === "chrome";
const stops = material === "aurora" ? AURORA : CHROME;
const liquidish = material === "mercury" || material === "liquid" || material === "glass";
 
// An inline <style> (not a class in a stylesheet), so that url(#…) points into this page's own document.
// Filters go on each top-level shape of an icon (not the <svg>), so their units are the icon's own 24-unit grid
// and a look is the same size-for-size at 16px or 160px.
let css = "";
if (material === "neon") {
css = `.${scope} svg{filter:drop-shadow(0 0 1.5px currentColor) drop-shadow(0 0 6px currentColor)}`;
} else if (flat) {
css =
`.${scope} svg *:not([stroke="none"]){stroke:url(#${scope}) !important}` +
`.${scope} svg *[fill]:not([fill="none"]){fill:url(#${scope}) !important}` +
(material === "chrome" ? `.${scope} svg{filter:drop-shadow(0 1px 1px rgba(0,0,0,.35))}` : "");
} else if (liquidish) {
css =
`.${scope} svg *:not([stroke="none"]){stroke:url(#${scope}) !important}` +
`.${scope} svg *[fill]:not([fill="none"]){fill:url(#${scope}) !important}` +
`.${scope} svg>*:not(defs){filter:url(#${scope}-f)}` +
(material === "liquid" && !reduce ? `.${scope} svg:hover>*:not(defs){filter:url(#${scope}-w)}` : "");
}
 
const flow = !reduce && (material === "mercury" || material === "glass");
 
return (
<div className={[scope, className].filter(Boolean).join(" ")} style={{ color, ...style }} data-material={material}>
{css ? <style>{css}</style> : null}
{flat ? (
<svg width="0" height="0" aria-hidden="true" style={{ position: "absolute" }} focusable="false">
<defs>
<linearGradient id={scope} gradientUnits="userSpaceOnUse" x1="3" y1="21" x2="21" y2="3">
{stops.map(([offset, c]) => (
<stop key={offset} offset={offset} stopColor={c} />
))}
</linearGradient>
</defs>
</svg>
) : null}
 
{material === "mercury" ? (
<svg width="0" height="0" aria-hidden="true" style={{ position: "absolute" }} focusable="false">
<defs>
{/* one stripe of reflected room, repeated, so sliding it by one period loops without a seam */}
<linearGradient id={scope} gradientUnits="userSpaceOnUse" x1="0" y1="24" x2="24" y2="0" spreadMethod="repeat">
{MERCURY.map(([offset, c]) => (
<stop key={offset} offset={offset} stopColor={c} />
))}
{flow ? <animateTransform attributeName="gradientTransform" type="translate" from="0 0" to="24 -24" dur="7s" repeatCount="indefinite" /> : null}
</linearGradient>
<filter id={`${scope}-f`} filterUnits="userSpaceOnUse" x="-4" y="-4" width="32" height="32" colorInterpolationFilters="sRGB">
{/* round the strokes off and let touching ones melt together */}
<feGaussianBlur in="SourceAlpha" stdDeviation="0.5" result="soft" />
<feColorMatrix in="soft" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 -6" result="shape" />
{/* a smooth height map of that shape, lit from the top left like a tube of metal */}
<feGaussianBlur in="shape" stdDeviation="0.65" result="relief" />
<feSpecularLighting in="relief" surfaceScale="2.6" specularConstant="1.2" specularExponent="28" lightingColor="#ffffff" result="shine">
<fePointLight x="3" y="0" z="13" />
</feSpecularLighting>
<feComposite in="shine" in2="shape" operator="in" result="glint" />
<feComposite in="SourceGraphic" in2="shape" operator="in" result="body" />
<feComposite in="body" in2="glint" operator="arithmetic" k1="0" k2="1" k3="0.9" k4="0" result="lit" />
<feDropShadow in="lit" dx="0" dy="0.5" stdDeviation="0.45" floodColor="#000000" floodOpacity="0.42" />
</filter>
</defs>
</svg>
) : null}
 
{material === "liquid" ? (
<svg width="0" height="0" aria-hidden="true" style={{ position: "absolute" }} focusable="false">
<defs>
<linearGradient id={scope} gradientUnits="userSpaceOnUse" x1="3" y1="3" x2="21" y2="21">
<stop offset="0" stopColor="currentColor" style={{ stopColor: "color-mix(in srgb, currentColor 55%, white)" }} />
<stop offset="0.5" stopColor="currentColor" />
<stop offset="1" stopColor="currentColor" style={{ stopColor: "color-mix(in srgb, currentColor 70%, black)" }} />
</linearGradient>
<filter id={`${scope}-f`} filterUnits="userSpaceOnUse" x="-4" y="-4" width="32" height="32" colorInterpolationFilters="sRGB">
<LiquidCore wobble={false} />
</filter>
<filter id={`${scope}-w`} filterUnits="userSpaceOnUse" x="-4" y="-4" width="32" height="32" colorInterpolationFilters="sRGB">
<LiquidCore wobble />
</filter>
</defs>
</svg>
) : null}
 
{material === "glass" ? (
<svg width="0" height="0" aria-hidden="true" style={{ position: "absolute" }} focusable="false">
<defs>
<linearGradient id={scope} gradientUnits="userSpaceOnUse" x1="0" y1="24" x2="24" y2="0" spreadMethod="repeat">
{GLASS.map(([offset, c, o]) => (
<stop key={offset} offset={offset} stopColor={c} stopOpacity={o} />
))}
{flow ? <animateTransform attributeName="gradientTransform" type="translate" from="0 0" to="24 -24" dur="9s" repeatCount="indefinite" /> : null}
</linearGradient>
<filter id={`${scope}-f`} filterUnits="userSpaceOnUse" x="-4" y="-4" width="32" height="32" colorInterpolationFilters="sRGB">
{/* a bright rim where the glass catches the light */}
<feGaussianBlur in="SourceAlpha" stdDeviation="0.3" result="soft" />
<feSpecularLighting in="soft" surfaceScale="2" specularConstant="1" specularExponent="13" lightingColor="#ffffff" result="rim">
<fePointLight x="2" y="0" z="9" />
</feSpecularLighting>
<feComposite in="rim" in2="SourceAlpha" operator="in" result="edge" />
{/* the lens bends red and blue light apart: a fringe on each side of every stroke */}
<feColorMatrix in="SourceGraphic" type="matrix" values="1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0" result="red" />
<feOffset in="red" dx="-0.32" dy="0" result="redShift" />
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0" result="green" />
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0" result="blue" />
<feOffset in="blue" dx="0.32" dy="0" result="blueShift" />
<feBlend in="redShift" in2="green" mode="screen" result="rg" />
<feBlend in="rg" in2="blueShift" mode="screen" result="split" />
<feComposite in="edge" in2="split" operator="arithmetic" k1="0" k2="0.9" k3="1" k4="0" result="glass" />
<feDropShadow in="glass" dx="0" dy="0.6" stdDeviation="0.55" floodColor="#0a1030" floodOpacity="0.5" />
</filter>
</defs>
</svg>
) : null}
 
{children}
</div>
);
}
 
/** The shared part of the liquid filter: melt, light, and (on hover) a slow jelly wobble. */
function LiquidCore({ wobble }: { wobble: boolean }) {
return (
<>
{wobble ? (
<>
<feTurbulence type="fractalNoise" baseFrequency="0.05 0.07" numOctaves="1" seed="3" result="noise">
<animate attributeName="baseFrequency" values="0.05 0.07;0.08 0.05;0.05 0.07" dur="2.6s" repeatCount="indefinite" />
</feTurbulence>
<feDisplacementMap in="SourceGraphic" in2="noise" scale="1.1" xChannelSelector="R" yChannelSelector="G" result="wobbled" />
</>
) : null}
<feGaussianBlur in={wobble ? "wobbled" : "SourceGraphic"} stdDeviation="0.7" result="soft" />
<feColorMatrix in="soft" type="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 22 -9" result="melted" />
<feGaussianBlur in="melted" stdDeviation="0.7" result="relief" />
<feSpecularLighting in="relief" surfaceScale="3" specularConstant="1.3" specularExponent="18" lightingColor="#ffffff" result="wet">
<fePointLight x="4" y="0" z="10" />
</feSpecularLighting>
<feComposite in="wet" in2="melted" operator="in" result="gloss" />
<feComposite in="melted" in2="gloss" operator="arithmetic" k1="0" k2="1" k3="0.95" k4="0" result="lit" />
<feDropShadow in="lit" dx="0" dy="0.55" stdDeviation="0.5" floodColor="currentColor" floodOpacity="0.45" />
</>
);
}
 

Questions about the gas pump icon

How do I use the gas pump icon in React?

Copy gas-pump.tsx into your project, install framer-motion, and import GasPumpIcon. Render it like any component: <GasPumpIcon size={32} />.

Where can I use the gas pump icon?

fuel price tracker, trip planner stop, find nearby stations, low fuel warning. Each one is shown live on this page.

Is the gas pump icon free?

You can preview and play the gas pump icon, with its looks and its sound, for free. Its code and sound file are part of Nexus UI Pro, which unlocks all 325 Pro icons. 75 other icons are free to copy.

Does it need a library?

Only Framer Motion, which draws the animation. The icon itself is one file of plain SVG and React, with no other dependencies.

Can I change the size and colour?

Yes. Set size (in pixels) and strokeWidth as props. The icon draws in currentColor, so a text colour class on it, or on a parent, changes its colour.

Does the gas pump icon make a sound?

Yes, optionally: A metal nozzle clunk as the hose starts to move, a run of mechanical counter ticks that follows the display filling, rubbery hose slaps at each twitch, fuel rushing through, and a shut-off clunk when the display is full. The sound is scored against the icon's own animation, so every note lands on a beat of the picture, and it follows the speed prop. It plays only if you call it, and it follows the visitor's sound setting.

What happens with reduced motion?

When the visitor has reduced motion switched on in their system, the icon does not animate. It stays in its resting pose.